From 6d5223738004ecfbfc0da8738cc7fa2f122ca140 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Mon, 29 Oct 2012 09:54:50 -0700 Subject: [PATCH 001/554] wip for new line rewriter --- moonscript/compile.lua | 207 ++++++++++++++++++++++++++++------------ moonscript/compile.moon | 126 +++++++++++++++++------- moonscript/errors.lua | 3 + moonscript/errors.moon | 1 + moonscript/parse.lua | 2 +- moonscript/util.lua | 2 +- moonscript/util.moon | 3 +- 7 files changed, 248 insertions(+), 96 deletions(-) diff --git a/moonscript/compile.lua b/moonscript/compile.lua index 102ac162..8d354b9e 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -17,7 +17,7 @@ do ntype = _table_0.ntype end local concat, insert = table.concat, table.insert -local pos_to_line, get_closest_line, trim = util.pos_to_line, util.get_closest_line, util.trim +local pos_to_line, get_line, get_closest_line, trim = util.pos_to_line, util.get_line, util.get_closest_line, util.trim local mtype = util.moon.type local Line Line = (function() @@ -123,7 +123,7 @@ Line = (function() return _class_0 end)() Block = (function() - local add_to_buffer + local add_to_buffer, block_iterator local _parent_0 = nil local _base_0 = { header = "do", @@ -260,54 +260,36 @@ Block = (function() }) return name end, - mark_pos = function(self, node) - if node[-1] then - self.last_pos = node[-1] - if not self._posmap[self.current_line] then - self._posmap[self.current_line] = self.last_pos + mark_pos = function(self, line_no, node) + do + local pos = node[-1] + if pos then + self.last_pos = pos + if not (self._posmap[line_no]) then + self._posmap[line_no] = pos + end end end end, + append_posmap = function(self, map) + print("appending pos", self) + self._posmap[#self._posmap + 1] = map + end, add_raw = function(self, item) return insert(self._lines, item) end, - append_line_table = function(self, sub_table, offset) - offset = offset + self.current_line - for line, source in pairs(sub_table) do - line = line + offset - if not self._posmap[line] then - self._posmap[line] = source - end - end - end, - add_line_tables = function(self, line) - local _list_0 = line - for _index_0 = 1, #_list_0 do - local chunk = _list_0[_index_0] - if util.moon.type(chunk) == Block then - local current = chunk - while current do - if util.moon.type(current.header) == Line then - self:add_line_tables(current.header) - end - self:append_line_table(current:line_table(), 0) - self.current_line = self.current_line + current.current_line - current = current.next - end - end - end - end, add = function(self, line) local _exp_0 = util.moon.type(line) if "string" == _exp_0 then - return insert(self._lines, line) + insert(self._lines, line) elseif Block == _exp_0 then - return line:render(self._lines) + line:render(self._lines) elseif Line == _exp_0 then - return line:render(self._lines) + line:render(self._lines) else - return error("Adding unknown item") + error("Adding unknown item") end + return line end, render = function(self, buffer) add_to_buffer(buffer, self.header) @@ -361,7 +343,6 @@ Block = (function() if type(node) ~= "table" then action = "raw_value" else - self:mark_pos(node) action = node[1] end local fn = value_compile[action] @@ -393,26 +374,50 @@ Block = (function() return end node = self.transform.statement(node) - local fn = line_compile[ntype(node)] - if not fn then - if has_value(node) then - self:stm({ - "assign", - { - "_" - }, - { - node - } - }) + local before = #self._lines + local added + do + local fn = line_compile[ntype(node)] + if fn then + local out = fn(self, node, ...) + if out then + added = self:add(out) + end else - self:add(self:value(node)) + if has_value(node) then + added = self:stm({ + "assign", + { + "_" + }, + { + node + } + }) + else + added = self:add(self:value(node)) + end end - else - self:mark_pos(node) - local out = fn(self, node, ...) - if out then - self:add(out) + end + if added then + print("added " .. tostring(#self._lines - before) .. " lines") + local list + if Line == mtype(added) then + list = added + else + list = { + added + } + end + local next_block = block_iterator(list) + for l = before + 1, #self._lines do + if "table" == type(self._lines[l]) then + local block = next_block() + block._posmap.num_lines = #block._lines + self._posmap[l] = block._posmap + else + self:mark_pos(l, node) + end end end return nil @@ -444,7 +449,6 @@ Block = (function() local _class_0 = setmetatable({ __init = function(self, parent, header, footer) self.parent, self.header, self.footer = parent, header, footer - self.current_line = 1 self._lines = { } self._posmap = { } self._names = { } @@ -499,6 +503,17 @@ Block = (function() end return buffer end + block_iterator = function(list) + return coroutine.wrap(function() + local _list_0 = list + for _index_0 = 1, #_list_0 do + local item = _list_0[_index_0] + if Block == mtype(item) then + coroutine.yield(item) + end + end + end) + end if _parent_0 and _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end @@ -534,6 +549,76 @@ flatten_lines = function(lines, indent, buffer) end return buffer end +local flatten_posmap +flatten_posmap = function(posmap, dl, out) + if dl == nil then + dl = 0 + end + if out == nil then + out = { } + end + for k, v in pairs(posmap) do + local _continue_0 = false + repeat + if "string" == type(k) then + _continue_0 = true + break + end + if "table" == type(v) then + flatten_posmap(v, k - 1 + dl, out) + dl = dl + (v.num_lines - 1) + else + out[k + dl] = v + end + _continue_0 = true + until true + if not _continue_0 then + break + end + end + return out +end +local debug_posmap +debug_posmap = function(posmap, fname, lua_code) + if fname == nil then + fname = error("pass in input file") + end + local moon_code = io.open(fname):read("*a") + local tuples = (function() + local _accum_0 = { } + local _len_0 = 0 + for k, v in pairs(posmap) do + _len_0 = _len_0 + 1 + _accum_0[_len_0] = { + k, + v + } + end + return _accum_0 + end)() + table.sort(tuples, function(a, b) + return a[1] < b[1] + end) + local lines = (function() + local _accum_0 = { } + local _len_0 = 0 + local _list_0 = tuples + for _index_0 = 1, #_list_0 do + local pair = _list_0[_index_0] + local lua_line, pos = unpack(pair) + local moon_line = pos_to_line(moon_code, pos) + local lua_text = get_line(lua_code, lua_line) + local moon_text = get_closest_line(moon_code, moon_line) + local _value_0 = tostring(pos) .. "\t " .. tostring(lua_line) .. ":[ " .. tostring(trim(lua_text)) .. " ] >> " .. tostring(moon_line) .. ":[ " .. tostring(trim(moon_text)) .. " ]" + if _value_0 ~= nil then + _len_0 = _len_0 + 1 + _accum_0[_len_0] = _value_0 + end + end + return _accum_0 + end)() + return concat(lines, "\n") .. "\n" +end RootBlock = (function() local _parent_0 = Block local _base_0 = { @@ -631,7 +716,11 @@ tree = function(tree, scope) end return nil, error_msg, scope.last_pos else - local tbl = scope:line_table() - return result, tbl + local raw_posmap = scope:line_table() + local posmap = flatten_posmap(raw_posmap) + print(util.dump(raw_posmap)) + print(util.dump(posmap)) + print(debug_posmap(posmap, "scrap.moon", result)) + return result, posmap end end diff --git a/moonscript/compile.moon b/moonscript/compile.moon index 4705960c..e9c47ee3 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -14,7 +14,7 @@ import Set from require "moonscript.data" import ntype from require "moonscript.types" import concat, insert from table -import pos_to_line, get_closest_line, trim from util +import pos_to_line, get_line, get_closest_line, trim from util mtype = util.moon.type @@ -82,8 +82,6 @@ class Block "Block<#{h}> <- " .. tostring @parent new: (@parent, @header, @footer) => - @current_line = 1 - @_lines = {} @_posmap = {} @_names = {} @@ -104,6 +102,8 @@ class Block else @indent = 0 + -- maps from a output (lua) line number to a character position in the + -- original moon file line_table: => @_posmap @@ -177,35 +177,38 @@ class Block @stm {"assign", {name}, {value}} name - mark_pos: (node) => - if node[-1] - @last_pos = node[-1] - if not @_posmap[@current_line] - @_posmap[@current_line] = @last_pos + mark_pos: (line_no, node) => + if pos = node[-1] + @last_pos = pos + @_posmap[line_no] = pos unless @_posmap[line_no] + + append_posmap: (map) => + print "appending pos", self + @_posmap[#@_posmap + 1] = map -- add raw text as new line add_raw: (item) => insert @_lines, item - append_line_table: (sub_table, offset) => - offset = offset + @current_line + -- append_line_table: (sub_table, offset) => + -- offset = offset + @current_line - for line, source in pairs sub_table - line += offset - if not @_posmap[line] - @_posmap[line] = source + -- for line, source in pairs sub_table + -- line += offset + -- if not @_posmap[line] + -- @_posmap[line] = source - add_line_tables: (line) => - for chunk in *line - if util.moon.type(chunk) == Block - current = chunk - while current - if util.moon.type(current.header) == Line - @add_line_tables current.header + -- add_line_tables: (line) => + -- for chunk in *line + -- if util.moon.type(chunk) == Block + -- current = chunk + -- while current + -- if util.moon.type(current.header) == Line + -- @add_line_tables current.header - @append_line_table current\line_table!, 0 - @current_line += current.current_line - current = current.next + -- @append_line_table current\line_table!, 0 + -- @current_line += current.current_line + -- current = current.next -- add a line object add: (line) => @@ -219,6 +222,7 @@ class Block line\render @_lines else error "Adding unknown item" + line add_to_buffer = (buffer, line) -> switch mtype line @@ -269,7 +273,6 @@ class Block action = if type(node) != "table" "raw_value" else - @mark_pos node node[1] fn = value_compile[action] @@ -281,20 +284,43 @@ class Block with Line! \append_list [@value v for v in *values], delim + + block_iterator = (list) -> + coroutine.wrap -> + for item in *list + if Block == mtype item + coroutine.yield item + stm: (node, ...) => return if not node -- skip blank statements node = @transform.statement node - fn = line_compile[ntype(node)] - if not fn + + before = #@_lines + + added = if fn = line_compile[ntype(node)] + out = fn self, node, ... + @add out if out + else -- coerce value into statement if has_value node @stm {"assign", {"_"}, {node}} else @add @value node - else - @mark_pos node - out = fn self, node, ... - @add out if out + + -- mark pos for each line added + if added + print "added #{#@_lines - before} lines" + + list = if Line == mtype added then added else {added} + next_block = block_iterator list + + for l=before + 1,#@_lines + if "table" == type @_lines[l] + block = next_block! + block._posmap.num_lines = #block._lines + @_posmap[l] = block._posmap + else + @mark_pos l, node nil stms: (stms, ret) => @@ -307,7 +333,6 @@ class Block @_lines = {} @stms fn lines - flatten_lines = (lines, indent=nil, buffer={}) -> for i = 1, #lines l = lines[i] @@ -329,6 +354,35 @@ flatten_lines = (lines, indent=nil, buffer={}) -> buffer +flatten_posmap = (posmap, dl=0, out={}) -> + for k,v in pairs posmap + continue if "string" == type k + if "table" == type v + flatten_posmap v, k - 1 + dl, out + dl += v.num_lines - 1 + else + out[k + dl] = v + + out + +debug_posmap = (posmap, fname=error"pass in input file", lua_code) -> + moon_code = io.open(fname)\read "*a" + + tuples = [{k, v} for k, v in pairs posmap] + + table.sort tuples, (a, b) -> a[1] < b[1] + + lines = for pair in *tuples + lua_line, pos = unpack pair + moon_line = pos_to_line moon_code, pos + + lua_text = get_line lua_code, lua_line + moon_text = get_closest_line moon_code, moon_line + + "#{pos}\t #{lua_line}:[ #{trim lua_text} ] >> #{moon_line}:[ #{trim moon_text} ]" + + concat(lines, "\n") .. "\n" + class RootBlock extends Block new: (...) => @root = self @@ -378,6 +432,10 @@ tree = (tree, scope=RootBlock!) -> nil, error_msg, scope.last_pos else - tbl = scope\line_table! - result, tbl + raw_posmap = scope\line_table! + posmap = flatten_posmap raw_posmap + print util.dump raw_posmap + print util.dump posmap + print debug_posmap posmap, "scrap.moon", result + result, posmap diff --git a/moonscript/errors.lua b/moonscript/errors.lua index cd2992e2..08c65e2c 100644 --- a/moonscript/errors.lua +++ b/moonscript/errors.lua @@ -73,6 +73,9 @@ rewrite_traceback = function(text, err) fname, ":", reverse_line_number(fname, tbl, line, cache), + "(", + line, + ")", ": ", msg }) diff --git a/moonscript/errors.moon b/moonscript/errors.moon index f6ba3e56..4b48021e 100644 --- a/moonscript/errors.moon +++ b/moonscript/errors.moon @@ -63,6 +63,7 @@ rewrite_traceback = (text, err) -> concat { fname, ":" reverse_line_number(fname, tbl, line, cache) + "(", line, ")" ": ", msg } else diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 7bd102ed..884edfb7 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -341,7 +341,7 @@ local build_grammar = wrap_env(function() CheckIndent = Cmt(Indent, check_indent), -- validates line is in correct indent Line = (CheckIndent * Statement + Space * #Stop), - Statement = ( + Statement = pos( Import + While + With + For + ForEach + Switch + Return + ClassDecl + Local + Export + BreakLoop + Ct(ExpList) * (Update + Assign)^-1 / format_assign diff --git a/moonscript/util.lua b/moonscript/util.lua index a052ba0f..d131a127 100644 --- a/moonscript/util.lua +++ b/moonscript/util.lua @@ -31,7 +31,7 @@ get_closest_line = function(str, line_num) end end get_line = function(str, line_num) - for line in str:gmatch("(.-)[\n$]") do + for line in str:gmatch("([^\n]*)\n?") do if line_num == 1 then return line end diff --git a/moonscript/util.moon b/moonscript/util.moon index f9927d55..3a97ffef 100644 --- a/moonscript/util.moon +++ b/moonscript/util.moon @@ -33,7 +33,8 @@ get_closest_line = (str, line_num) -> line, line_num get_line = (str, line_num) -> - for line in str\gmatch "(.-)[\n$]" + -- todo: this returns an extra blank line at the end + for line in str\gmatch "([^\n]*)\n?" return line if line_num == 1 line_num -= 1 From 05d83f399d8c28f8059204eac44aedc3baa3ae59 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Mon, 29 Oct 2012 22:15:06 -0700 Subject: [PATCH 002/554] add Lines --- moonscript/compile.lua | 134 +++++++++++++++++++----------- moonscript/compile.moon | 90 ++++++++++---------- moonscript/compile/statement.lua | 2 +- moonscript/compile/statement.moon | 2 +- 4 files changed, 135 insertions(+), 93 deletions(-) diff --git a/moonscript/compile.lua b/moonscript/compile.lua index 8d354b9e..87bd1730 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -19,7 +19,75 @@ end local concat, insert = table.concat, table.insert local pos_to_line, get_line, get_closest_line, trim = util.pos_to_line, util.get_line, util.get_closest_line, util.trim local mtype = util.moon.type -local Line +local Line, Lines +Lines = (function() + local _parent_0 = nil + local _base_0 = { + add = function(self, item) + local _exp_0 = mtype(item) + if Line == _exp_0 then + item:render(self) + elseif Block == _exp_0 then + item:render(self) + else + self[#self + 1] = item + end + return self + end, + __tostring = function(self) + local strip + strip = function(t) + if "table" == type(t) then + return (function() + local _accum_0 = { } + local _len_0 = 0 + local _list_0 = t + for _index_0 = 1, #_list_0 do + local v = _list_0[_index_0] + _len_0 = _len_0 + 1 + _accum_0[_len_0] = strip(v) + end + return _accum_0 + end)() + else + return t + end + end + return "Lines<" .. tostring(util.dump(strip(self)):sub(1, -2)) .. ">" + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.posmap = { } + end, + __base = _base_0, + __name = "Lines", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + return _class_0 +end)() Line = (function() local _parent_0 = nil local _base_0 = { @@ -57,21 +125,21 @@ Line = (function() local current = { } local add_current add_current = function() - return insert(buffer, concat(current)) + return buffer:add(concat(current)) end local _list_0 = self for _index_0 = 1, #_list_0 do local chunk = _list_0[_index_0] local _exp_0 = mtype(chunk) if Block == _exp_0 then - local _list_1 = chunk:render({ }) + local _list_1 = chunk:render(Lines()) for _index_1 = 1, #_list_1 do local block_chunk = _list_1[_index_1] if "string" == type(block_chunk) then insert(current, block_chunk) else add_current() - insert(buffer, block_chunk) + buffer:add(block_chunk) current = { } end end @@ -85,7 +153,7 @@ Line = (function() return buffer end, __tostring = function(self) - return "Line<" .. tostring(self:render()) .. ">" + return "Line<" .. tostring(util.dump(self):sub(1, -2)) .. ">" end } _base_0.__index = _base_0 @@ -123,7 +191,7 @@ Line = (function() return _class_0 end)() Block = (function() - local add_to_buffer, block_iterator + local block_iterator local _parent_0 = nil local _base_0 = { header = "do", @@ -275,44 +343,21 @@ Block = (function() print("appending pos", self) self._posmap[#self._posmap + 1] = map end, - add_raw = function(self, item) - return insert(self._lines, item) - end, - add = function(self, line) - local _exp_0 = util.moon.type(line) - if "string" == _exp_0 then - insert(self._lines, line) - elseif Block == _exp_0 then - line:render(self._lines) - elseif Line == _exp_0 then - line:render(self._lines) - else - error("Adding unknown item") - end - return line + add = function(self, item) + self._lines:add(item) + return item end, render = function(self, buffer) - add_to_buffer(buffer, self.header) - local lines = (function() - local _accum_0 = { } - local _len_0 = 0 - local _list_0 = self._lines - for _index_0 = 1, #_list_0 do - local l = _list_0[_index_0] - _len_0 = _len_0 + 1 - _accum_0[_len_0] = l - end - return _accum_0 - end)() + buffer:add(self.header) if self.next then - insert(buffer, lines) + buffer:add(self._lines) self.next:render(buffer) else - if #lines == 0 and "string" == type(buffer[#buffer]) then - buffer[#buffer] = buffer[#buffer] .. (" " .. (unpack(add_to_buffer({ }, self.footer)))) + if #self._lines == 0 and "string" == type(buffer[#buffer]) then + buffer[#buffer] = buffer[#buffer] .. (" " .. (unpack(Lines():add(self.footer)))) else - insert(buffer, lines) - add_to_buffer(buffer, self.footer) + buffer:add(self._lines) + buffer:add(self.footer) end end return buffer @@ -438,7 +483,7 @@ Block = (function() "lines", self._lines } - self._lines = { } + self._lines = Lines() return self:stms(fn(lines)) end } @@ -449,7 +494,7 @@ Block = (function() local _class_0 = setmetatable({ __init = function(self, parent, header, footer) self.parent, self.header, self.footer = parent, header, footer - self._lines = { } + self._lines = Lines() self._posmap = { } self._names = { } self._state = { } @@ -494,15 +539,6 @@ Block = (function() }) _base_0.__class = _class_0 local self = _class_0 - add_to_buffer = function(buffer, line) - local _exp_0 = mtype(line) - if Line == _exp_0 then - line:render(buffer) - else - insert(buffer, line) - end - return buffer - end block_iterator = function(list) return coroutine.wrap(function() local _list_0 = list diff --git a/moonscript/compile.moon b/moonscript/compile.moon index e9c47ee3..67f985df 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -21,7 +21,34 @@ mtype = util.moon.type export tree, value, format_error export Block, RootBlock --- buffer for building up a line +local Line, Lines + +-- a buffer for building up lines +class Lines + new: => + @posmap = {} + + -- append a line or lines to the buffer + add: (item) => + switch mtype item + when Line + item\render self + when Block + item\render self + else + @[#@ + 1] = item + @ + + __tostring: => + -- strip non-array elements + strip = (t) -> + if "table" == type t + [strip v for v in *t] + else + t + + -- copy with only array elements + "Lines<#{util.dump(strip @)\sub 1, -2}>" class Line _append_single: (item) => if util.moon.type(item) == Line @@ -39,22 +66,22 @@ class Line @_append_single item for item in *{...} nil - -- todo: remove concats from here + -- todo: try to remove concats from here render: (buffer) => current = {} add_current = -> - insert buffer, concat current + buffer\add concat current for chunk in *@ switch mtype chunk when Block - for block_chunk in *chunk\render{} + for block_chunk in *chunk\render Lines! if "string" == type block_chunk insert current, block_chunk else add_current! - insert buffer, block_chunk + buffer\add block_chunk current = {} else insert current, chunk @@ -64,7 +91,8 @@ class Line buffer - __tostring: => "Line<#{@render!}>" + __tostring: => + "Line<#{util.dump(@)\sub 1, -2}>" class Block header: "do" @@ -82,8 +110,9 @@ class Block "Block<#{h}> <- " .. tostring @parent new: (@parent, @header, @footer) => - @_lines = {} - @_posmap = {} + @_lines = Lines! + + @_posmap = {} -- todo: kill me @_names = {} @_state = {} @_listeners = {} @@ -186,10 +215,6 @@ class Block print "appending pos", self @_posmap[#@_posmap + 1] = map - -- add raw text as new line - add_raw: (item) => - insert @_lines, item - -- append_line_table: (sub_table, offset) => -- offset = offset + @current_line @@ -211,44 +236,24 @@ class Block -- current = current.next -- add a line object - add: (line) => - -- print "adding", line - switch util.moon.type line - when "string" - insert @_lines, line - when Block - line\render @_lines - when Line - line\render @_lines - else - error "Adding unknown item" - line - - add_to_buffer = (buffer, line) -> - switch mtype line - when Line - line\render buffer - else - insert buffer, line - buffer + add: (item) => + @_lines\add item + item -- todo: pass in buffer as argument render: (buffer) => - add_to_buffer buffer, @header - - -- copy lines - lines = [l for l in *@_lines] + buffer\add @header if @next - insert buffer, lines + buffer\add @_lines @next\render buffer else -- join an empty block into a single line - if #lines == 0 and "string" == type buffer[#buffer] - buffer[#buffer] ..= " " .. (unpack add_to_buffer {}, @footer) + if #@_lines == 0 and "string" == type buffer[#buffer] + buffer[#buffer] ..= " " .. (unpack Lines!\add @footer) else - insert buffer, lines - add_to_buffer buffer, @footer + buffer\add @_lines + buffer\add @footer buffer @@ -330,9 +335,10 @@ class Block splice: (fn) => lines = {"lines", @_lines} - @_lines = {} + @_lines = Lines! @stms fn lines +-- move this into Lines flatten_lines = (lines, indent=nil, buffer={}) -> for i = 1, #lines l = lines[i] diff --git a/moonscript/compile/statement.lua b/moonscript/compile/statement.lua index 45277581..0a5039e2 100644 --- a/moonscript/compile/statement.lua +++ b/moonscript/compile/statement.lua @@ -18,7 +18,7 @@ line_compile = { local _list_0 = node[2] for _index_0 = 1, #_list_0 do local line = _list_0[_index_0] - self:add_raw(line) + self:add(line) end end, declare = function(self, node) diff --git a/moonscript/compile/statement.moon b/moonscript/compile/statement.moon index 3c20bd1f..0f48f2aa 100644 --- a/moonscript/compile/statement.moon +++ b/moonscript/compile/statement.moon @@ -17,7 +17,7 @@ line_compile = lines: (node) => for line in *node[2] - @add_raw line + @add line declare: (node) => names = node[2] From db1081f8e5cbeefcedf6a11d4568043a92565179 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 30 Oct 2012 00:20:25 -0700 Subject: [PATCH 003/554] new posmaps --- moonscript/compile.lua | 220 ++++++++++++++++++---------------------- moonscript/compile.moon | 183 +++++++++++++++------------------ moonscript/parse.lua | 2 +- 3 files changed, 179 insertions(+), 226 deletions(-) diff --git a/moonscript/compile.lua b/moonscript/compile.lua index 87bd1730..1d47f570 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -23,6 +23,14 @@ local Line, Lines Lines = (function() local _parent_0 = nil local _base_0 = { + mark_pos = function(self, pos, line) + if line == nil then + line = #self + end + if not (self.posmap[line]) then + self.posmap[line] = pos + end + end, add = function(self, item) local _exp_0 = mtype(item) if Line == _exp_0 then @@ -34,6 +42,55 @@ Lines = (function() end return self end, + flatten_posmap = function(self, line_no, out) + if line_no == nil then + line_no = 0 + end + if out == nil then + out = { } + end + local posmap = self.posmap + for i, l in ipairs(self) do + local _exp_0 = type(l) + if "table" == _exp_0 then + local _ + _, line_no = l:flatten_posmap(line_no, out) + elseif "string" == _exp_0 then + line_no = line_no + 1 + out[line_no] = posmap[i] + end + end + return out, line_no + end, + flatten = function(self, indent, buffer) + if indent == nil then + indent = nil + end + if buffer == nil then + buffer = { } + end + for i = 1, #self do + local l = self[i] + local _exp_0 = type(l) + if "string" == _exp_0 then + if indent then + insert(buffer, indent) + end + insert(buffer, l) + if "string" == type(self[i + 1]) then + local lc = l:sub(-1) + if (lc == ")" or lc == "]") and self[i + 1]:sub(1, 1) == "(" then + insert(buffer, ";") + end + end + insert(buffer, "\n") + local last = l + elseif "table" == _exp_0 then + l:flatten(indent and indent .. indent_char or indent_char, buffer) + end + end + return buffer + end, __tostring = function(self) local strip strip = function(t) @@ -91,8 +148,12 @@ end)() Line = (function() local _parent_0 = nil local _base_0 = { + pos = nil, _append_single = function(self, item) - if util.moon.type(item) == Line then + if Line == mtype(item) then + if not (self.pos) then + self.pos = item.pos + end local _list_0 = item for _index_0 = 1, #_list_0 do value = _list_0[_index_0] @@ -110,6 +171,7 @@ Line = (function() insert(self, delim) end end + return nil end, append = function(self, ...) local _list_0 = { @@ -125,7 +187,8 @@ Line = (function() local current = { } local add_current add_current = function() - return buffer:add(concat(current)) + buffer:add(concat(current)) + return buffer:mark_pos(self.pos) end local _list_0 = self for _index_0 = 1, #_list_0 do @@ -207,9 +270,6 @@ Block = (function() end return "Block<" .. tostring(h) .. "> <- " .. tostring(self.parent) end, - line_table = function(self) - return self._posmap - end, set = function(self, name, value) self._state[name] = value end, @@ -239,7 +299,7 @@ Block = (function() local name = _list_0[_index_0] local is_local = false local real_name - local _exp_0 = util.moon.type(name) + local _exp_0 = mtype(name) if LocalName == _exp_0 then is_local = true real_name = name:get_name(self) @@ -274,7 +334,7 @@ Block = (function() if select("#", ...) == 0 then value = true end - if util.moon.type(name) == NameProxy then + if NameProxy == mtype(name) then name = name:get_name(self) end self._names[name] = value @@ -328,27 +388,13 @@ Block = (function() }) return name end, - mark_pos = function(self, line_no, node) - do - local pos = node[-1] - if pos then - self.last_pos = pos - if not (self._posmap[line_no]) then - self._posmap[line_no] = pos - end - end - end - end, - append_posmap = function(self, map) - print("appending pos", self) - self._posmap[#self._posmap + 1] = map - end, add = function(self, item) self._lines:add(item) return item end, render = function(self, buffer) buffer:add(self.header) + buffer:mark_pos(self.pos) if self.next then buffer:add(self._lines) self.next:render(buffer) @@ -358,6 +404,7 @@ Block = (function() else buffer:add(self._lines) buffer:add(self.footer) + buffer:mark_pos(self.pos) end end return buffer @@ -394,7 +441,18 @@ Block = (function() if not fn then error("Failed to compile value: " .. dump.value(node)) end - return fn(self, node, ...) + local out = fn(self, node, ...) + if type(node) == "table" and node[-1] then + if type(out) == "string" then + do + local _with_0 = Line() + _with_0:append(out) + out = _with_0 + end + end + out.pos = node[-1] + end + return out end, values = function(self, values, delim) delim = delim or ', ' @@ -420,17 +478,14 @@ Block = (function() end node = self.transform.statement(node) local before = #self._lines - local added + local result do local fn = line_compile[ntype(node)] if fn then - local out = fn(self, node, ...) - if out then - added = self:add(out) - end + result = fn(self, node, ...) else if has_value(node) then - added = self:stm({ + result = self:stm({ "assign", { "_" @@ -440,30 +495,15 @@ Block = (function() } }) else - added = self:add(self:value(node)) + result = self:value(node) end end end - if added then - print("added " .. tostring(#self._lines - before) .. " lines") - local list - if Line == mtype(added) then - list = added - else - list = { - added - } - end - local next_block = block_iterator(list) - for l = before + 1, #self._lines do - if "table" == type(self._lines[l]) then - local block = next_block() - block._posmap.num_lines = #block._lines - self._posmap[l] = block._posmap - else - self:mark_pos(l, node) - end + if result then + if type(node) == "table" and type(result) == "table" and node[-1] then + result.pos = node[-1] end + self:add(result) end return nil end, @@ -495,7 +535,6 @@ Block = (function() __init = function(self, parent, header, footer) self.parent, self.header, self.footer = parent, header, footer self._lines = Lines() - self._posmap = { } self._names = { } self._state = { } self._listeners = { } @@ -555,65 +594,6 @@ Block = (function() end return _class_0 end)() -local flatten_lines -flatten_lines = function(lines, indent, buffer) - if indent == nil then - indent = nil - end - if buffer == nil then - buffer = { } - end - for i = 1, #lines do - local l = lines[i] - local _exp_0 = type(l) - if "string" == _exp_0 then - if indent then - insert(buffer, indent) - end - insert(buffer, l) - if "string" == type(lines[i + 1]) then - local lc = l:sub(-1) - if (lc == ")" or lc == "]") and lines[i + 1]:sub(1, 1) == "(" then - insert(buffer, ";") - end - end - insert(buffer, "\n") - local last = l - elseif "table" == _exp_0 then - flatten_lines(l, indent and indent .. indent_char or indent_char, buffer) - end - end - return buffer -end -local flatten_posmap -flatten_posmap = function(posmap, dl, out) - if dl == nil then - dl = 0 - end - if out == nil then - out = { } - end - for k, v in pairs(posmap) do - local _continue_0 = false - repeat - if "string" == type(k) then - _continue_0 = true - break - end - if "table" == type(v) then - flatten_posmap(v, k - 1 + dl, out) - dl = dl + (v.num_lines - 1) - else - out[k + dl] = v - end - _continue_0 = true - until true - if not _continue_0 then - break - end - end - return out -end local debug_posmap debug_posmap = function(posmap, fname, lua_code) if fname == nil then @@ -662,7 +642,7 @@ RootBlock = (function() return "RootBlock<>" end, render = function(self) - local buffer = flatten_lines(self._lines) + local buffer = self._lines:flatten() if buffer[#buffer] == "\n" then buffer[#buffer] = nil end @@ -732,31 +712,27 @@ tree = function(tree, scope) local line = _list_0[_index_0] scope:stm(line) end - return scope:render() end) - local success, result = coroutine.resume(runner) + local success, err = coroutine.resume(runner) if not success then local error_msg - if type(result) == "table" then - local error_type = result[1] + if type(err) == "table" then + local error_type = err[1] if error_type == "user-error" then - error_msg = result[2] + error_msg = err[2] else error_msg = error("Unknown error thrown", util.dump(error_msg)) end else error_msg = concat({ - result, + err, debug.traceback(runner) }, "\n") end return nil, error_msg, scope.last_pos else - local raw_posmap = scope:line_table() - local posmap = flatten_posmap(raw_posmap) - print(util.dump(raw_posmap)) - print(util.dump(posmap)) - print(debug_posmap(posmap, "scrap.moon", result)) - return result, posmap + local lua_code = scope:render() + local posmap = scope._lines:flatten_posmap() + return lua_code, posmap end end diff --git a/moonscript/compile.moon b/moonscript/compile.moon index 67f985df..2c86a3f4 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -28,6 +28,9 @@ class Lines new: => @posmap = {} + mark_pos: (pos, line=#@) => + @posmap[line] = pos unless @posmap[line] + -- append a line or lines to the buffer add: (item) => switch mtype item @@ -39,6 +42,38 @@ class Lines @[#@ + 1] = item @ + flatten_posmap: (line_no=0, out={}) => + posmap = @posmap + for i, l in ipairs @ + switch type l + when "table" + _, line_no = l\flatten_posmap line_no, out + when "string" + line_no += 1 + out[line_no] = posmap[i] + + out, line_no + + flatten: (indent=nil, buffer={}) => + for i = 1, #@ + l = @[i] + switch type l + when "string" + insert buffer, indent if indent + insert buffer, l + + -- insert breaks between ambiguous statements + if "string" == type @[i + 1] + lc = l\sub(-1) + if (lc == ")" or lc == "]") and @[i + 1]\sub(1,1) == "(" + insert buffer, ";" + + insert buffer, "\n" + last = l + when "table" + l\flatten indent and indent .. indent_char or indent_char, buffer + buffer + __tostring: => -- strip non-array elements strip = (t) -> @@ -49,9 +84,17 @@ class Lines -- copy with only array elements "Lines<#{util.dump(strip @)\sub 1, -2}>" + +-- Buffer for building up a line +-- A plain old table holding either strings or Block objects. +-- Adding a line to a line will cause that line to be merged in. class Line + pos: nil + _append_single: (item) => - if util.moon.type(item) == Line + if Line == mtype item + -- print "appending line to line", item.pos, item + @pos = item.pos unless @pos -- bubble pos if there isn't one @_append_single value for value in *item else insert self, item @@ -61,6 +104,7 @@ class Line for i = 1,#items @_append_single items[i] if i < #items then insert self, delim + nil append: (...) => @_append_single item for item in *{...} @@ -72,6 +116,7 @@ class Line add_current = -> buffer\add concat current + buffer\mark_pos @pos for chunk in *@ switch mtype chunk @@ -112,7 +157,6 @@ class Block new: (@parent, @header, @footer) => @_lines = Lines! - @_posmap = {} -- todo: kill me @_names = {} @_state = {} @_listeners = {} @@ -131,11 +175,6 @@ class Block else @indent = 0 - -- maps from a output (lua) line number to a character position in the - -- original moon file - line_table: => - @_posmap - set: (name, value) => @_state[name] = value @@ -155,7 +194,7 @@ class Block declare: (names) => undeclared = for name in *names is_local = false - real_name = switch util.moon.type name + real_name = switch mtype name when LocalName is_local = true name\get_name self @@ -174,7 +213,7 @@ class Block value = ... value = true if select("#", ...) == 0 - name = name\get_name self if util.moon.type(name) == NameProxy + name = name\get_name self if NameProxy == mtype name @_names[name] = value has_name: (name, skip_exports) => @@ -206,35 +245,6 @@ class Block @stm {"assign", {name}, {value}} name - mark_pos: (line_no, node) => - if pos = node[-1] - @last_pos = pos - @_posmap[line_no] = pos unless @_posmap[line_no] - - append_posmap: (map) => - print "appending pos", self - @_posmap[#@_posmap + 1] = map - - -- append_line_table: (sub_table, offset) => - -- offset = offset + @current_line - - -- for line, source in pairs sub_table - -- line += offset - -- if not @_posmap[line] - -- @_posmap[line] = source - - -- add_line_tables: (line) => - -- for chunk in *line - -- if util.moon.type(chunk) == Block - -- current = chunk - -- while current - -- if util.moon.type(current.header) == Line - -- @add_line_tables current.header - - -- @append_line_table current\line_table!, 0 - -- @current_line += current.current_line - -- current = current.next - -- add a line object add: (item) => @_lines\add item @@ -243,6 +253,9 @@ class Block -- todo: pass in buffer as argument render: (buffer) => buffer\add @header + buffer\mark_pos @pos + + -- print "Header:", util.dump(@header), mtype(@header).__name if @next buffer\add @_lines @@ -254,6 +267,7 @@ class Block else buffer\add @_lines buffer\add @footer + buffer\mark_pos @pos buffer @@ -282,7 +296,16 @@ class Block fn = value_compile[action] error "Failed to compile value: "..dump.value node if not fn - fn self, node, ... + + out = fn self, node, ... + + -- store the pos, creating a line if necessary + if type(node) == "table" and node[-1] + if type(out) == "string" + out = with Line! do \append out + out.pos = node[-1] + + out values: (values, delim) => delim = delim or ', ' @@ -302,30 +325,20 @@ class Block before = #@_lines - added = if fn = line_compile[ntype(node)] - out = fn self, node, ... - @add out if out + result = if fn = line_compile[ntype(node)] + fn self, node, ... else -- coerce value into statement if has_value node @stm {"assign", {"_"}, {node}} else - @add @value node - - -- mark pos for each line added - if added - print "added #{#@_lines - before} lines" + @value node - list = if Line == mtype added then added else {added} - next_block = block_iterator list + if result + if type(node) == "table" and type(result) == "table" and node[-1] + result.pos = node[-1] + @add result - for l=before + 1,#@_lines - if "table" == type @_lines[l] - block = next_block! - block._posmap.num_lines = #block._lines - @_posmap[l] = block._posmap - else - @mark_pos l, node nil stms: (stms, ret) => @@ -338,39 +351,6 @@ class Block @_lines = Lines! @stms fn lines --- move this into Lines -flatten_lines = (lines, indent=nil, buffer={}) -> - for i = 1, #lines - l = lines[i] - switch type l - when "string" - insert buffer, indent if indent - insert buffer, l - - -- insert breaks between ambiguous statements - if "string" == type lines[i + 1] - lc = l\sub(-1) - if (lc == ")" or lc == "]") and lines[i + 1]\sub(1,1) == "(" - insert buffer, ";" - - insert buffer, "\n" - last = l - when "table" - flatten_lines l, indent and indent .. indent_char or indent_char, buffer - - buffer - -flatten_posmap = (posmap, dl=0, out={}) -> - for k,v in pairs posmap - continue if "string" == type k - if "table" == type v - flatten_posmap v, k - 1 + dl, out - dl += v.num_lines - 1 - else - out[k + dl] = v - - out - debug_posmap = (posmap, fname=error"pass in input file", lua_code) -> moon_code = io.open(fname)\read "*a" @@ -397,8 +377,8 @@ class RootBlock extends Block __tostring: => "RootBlock<>" render: => - -- print util.dump @_lines - buffer = flatten_lines @_lines + -- print @_lines + buffer = @_lines\flatten! buffer[#buffer] = nil if buffer[#buffer] == "\n" table.concat buffer @@ -423,25 +403,22 @@ tree = (tree, scope=RootBlock!) -> runner = coroutine.create -> scope\stm line for line in *tree - scope\render! - success, result = coroutine.resume runner + success, err = coroutine.resume runner if not success - error_msg = if type(result) == "table" - error_type = result[1] + error_msg = if type(err) == "table" + error_type = err[1] if error_type == "user-error" - result[2] + err[2] else error "Unknown error thrown", util.dump error_msg else - concat {result, debug.traceback runner}, "\n" + concat {err, debug.traceback runner}, "\n" nil, error_msg, scope.last_pos else - raw_posmap = scope\line_table! - posmap = flatten_posmap raw_posmap - print util.dump raw_posmap - print util.dump posmap - print debug_posmap posmap, "scrap.moon", result - result, posmap + lua_code = scope\render! + posmap = scope._lines\flatten_posmap! + -- print debug_posmap posmap, "scrap.moon", lua_code + lua_code, posmap diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 884edfb7..f736f630 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -383,7 +383,7 @@ local build_grammar = wrap_env(function() IfCond = Exp * Assign^-1 / format_assign_for_if, If = key"if" * IfCond * key"then"^-1 * Body * - ((Break * CheckIndent)^-1 * EmptyLine^0 * key"elseif" * IfCond * key"then"^-1 * Body / mark"elseif")^0 * + ((Break * CheckIndent)^-1 * EmptyLine^0 * key"elseif" * pos(IfCond) * key"then"^-1 * Body / mark"elseif")^0 * ((Break * CheckIndent)^-1 * EmptyLine^0 * key"else" * Body / mark"else")^-1 / mark"if", Unless = key"unless" * IfCond * key"then"^-1 * Body * From bd93b322d04644793fd3831b2f20ec3390e7280c Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 30 Oct 2012 00:31:56 -0700 Subject: [PATCH 004/554] add -X flag to moonc to dump posmap --- bin/moonc | 15 ++++++++++++--- moonscript/compile.lua | 41 ----------------------------------------- moonscript/compile.moon | 19 ------------------- moonscript/util.lua | 36 ++++++++++++++++++++++++++++++++++++ moonscript/util.moon | 18 +++++++++++++++++- 5 files changed, 65 insertions(+), 64 deletions(-) diff --git a/bin/moonc b/bin/moonc index f18d43f5..9410d2e4 100755 --- a/bin/moonc +++ b/bin/moonc @@ -9,7 +9,7 @@ require "moonscript.util" require "alt_getopt" require "lfs" -local opts, ind = alt_getopt.get_opts(arg, "vhwt:pTb", { +local opts, ind = alt_getopt.get_opts(arg, "vhwt:pTXb", { print = "p", tree = "T", version = "v", help = "h" }) @@ -24,6 +24,7 @@ local help = [[Usage: %s [options] files... -t path Specify where to place compiled files -p Write output to standard out -T Write parse tree instead of code (to stdout) + -X Write line rewrite map instead of code (to stdout) -b Dump parse and compile time (doesn't write output) -v Print version @@ -122,10 +123,18 @@ function compile_file(text, fname) return "" else local compile_time = gettime() - local code, err, pos = compile.tree(tree) + local code, posmap_or_err, err_pos = compile.tree(tree) compile_time = gettime() - compile_time + if not code then - return nil, compile.format_error(err, pos, text) + return nil, compile.format_error(posmap_or_err, err_pos, text) + end + + if opts.X then + opts.p = true + print("Pos", "Lua", ">>", "Moon") + print(util.debug_posmap(posmap_or_err, text, code)) + return "" end if opts.b then diff --git a/moonscript/compile.lua b/moonscript/compile.lua index 1d47f570..075b4732 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -594,47 +594,6 @@ Block = (function() end return _class_0 end)() -local debug_posmap -debug_posmap = function(posmap, fname, lua_code) - if fname == nil then - fname = error("pass in input file") - end - local moon_code = io.open(fname):read("*a") - local tuples = (function() - local _accum_0 = { } - local _len_0 = 0 - for k, v in pairs(posmap) do - _len_0 = _len_0 + 1 - _accum_0[_len_0] = { - k, - v - } - end - return _accum_0 - end)() - table.sort(tuples, function(a, b) - return a[1] < b[1] - end) - local lines = (function() - local _accum_0 = { } - local _len_0 = 0 - local _list_0 = tuples - for _index_0 = 1, #_list_0 do - local pair = _list_0[_index_0] - local lua_line, pos = unpack(pair) - local moon_line = pos_to_line(moon_code, pos) - local lua_text = get_line(lua_code, lua_line) - local moon_text = get_closest_line(moon_code, moon_line) - local _value_0 = tostring(pos) .. "\t " .. tostring(lua_line) .. ":[ " .. tostring(trim(lua_text)) .. " ] >> " .. tostring(moon_line) .. ":[ " .. tostring(trim(moon_text)) .. " ]" - if _value_0 ~= nil then - _len_0 = _len_0 + 1 - _accum_0[_len_0] = _value_0 - end - end - return _accum_0 - end)() - return concat(lines, "\n") .. "\n" -end RootBlock = (function() local _parent_0 = Block local _base_0 = { diff --git a/moonscript/compile.moon b/moonscript/compile.moon index 2c86a3f4..6538c97c 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -351,24 +351,6 @@ class Block @_lines = Lines! @stms fn lines -debug_posmap = (posmap, fname=error"pass in input file", lua_code) -> - moon_code = io.open(fname)\read "*a" - - tuples = [{k, v} for k, v in pairs posmap] - - table.sort tuples, (a, b) -> a[1] < b[1] - - lines = for pair in *tuples - lua_line, pos = unpack pair - moon_line = pos_to_line moon_code, pos - - lua_text = get_line lua_code, lua_line - moon_text = get_closest_line moon_code, moon_line - - "#{pos}\t #{lua_line}:[ #{trim lua_text} ] >> #{moon_line}:[ #{trim moon_text} ]" - - concat(lines, "\n") .. "\n" - class RootBlock extends Block new: (...) => @root = self @@ -419,6 +401,5 @@ tree = (tree, scope=RootBlock!) -> else lua_code = scope\render! posmap = scope._lines\flatten_posmap! - -- print debug_posmap posmap, "scrap.moon", lua_code lua_code, posmap diff --git a/moonscript/util.lua b/moonscript/util.lua index d131a127..e9845e96 100644 --- a/moonscript/util.lua +++ b/moonscript/util.lua @@ -99,3 +99,39 @@ dump = function(what) end return _dump(what) end +debug_posmap = function(posmap, moon_code, lua_code) + local tuples = (function() + local _accum_0 = { } + local _len_0 = 0 + for k, v in pairs(posmap) do + _len_0 = _len_0 + 1 + _accum_0[_len_0] = { + k, + v + } + end + return _accum_0 + end)() + table.sort(tuples, function(a, b) + return a[1] < b[1] + end) + local lines = (function() + local _accum_0 = { } + local _len_0 = 0 + local _list_0 = tuples + for _index_0 = 1, #_list_0 do + local pair = _list_0[_index_0] + local lua_line, pos = unpack(pair) + local moon_line = pos_to_line(moon_code, pos) + local lua_text = get_line(lua_code, lua_line) + local moon_text = get_closest_line(moon_code, moon_line) + local _value_0 = tostring(pos) .. "\t " .. tostring(lua_line) .. ":[ " .. tostring(trim(lua_text)) .. " ] >> " .. tostring(moon_line) .. ":[ " .. tostring(trim(moon_text)) .. " ]" + if _value_0 ~= nil then + _len_0 = _len_0 + 1 + _accum_0[_len_0] = _value_0 + end + end + return _accum_0 + end)() + return concat(lines, "\n") +end diff --git a/moonscript/util.moon b/moonscript/util.moon index 3a97ffef..7bbb8c12 100644 --- a/moonscript/util.moon +++ b/moonscript/util.moon @@ -4,7 +4,7 @@ module "moonscript.util", package.seeall export moon export pos_to_line, get_closest_line, get_line export reversed, trim, split -export dump +export dump, debug_posmap import concat from table @@ -75,3 +75,19 @@ dump = (what) -> _dump what +debug_posmap = (posmap, moon_code, lua_code) -> + tuples = [{k, v} for k, v in pairs posmap] + table.sort tuples, (a, b) -> a[1] < b[1] + + lines = for pair in *tuples + lua_line, pos = unpack pair + moon_line = pos_to_line moon_code, pos + + lua_text = get_line lua_code, lua_line + moon_text = get_closest_line moon_code, moon_line + + "#{pos}\t #{lua_line}:[ #{trim lua_text} ] >> #{moon_line}:[ #{trim moon_text} ]" + + concat(lines, "\n") + + From ef4157fb5feedffb72521e77881842c592844de1 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 30 Oct 2012 00:34:39 -0700 Subject: [PATCH 005/554] cleanup --- moonscript/compile.lua | 16 +--------------- moonscript/compile.moon | 14 +------------- 2 files changed, 2 insertions(+), 28 deletions(-) diff --git a/moonscript/compile.lua b/moonscript/compile.lua index 075b4732..f9b1b811 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -17,7 +17,7 @@ do ntype = _table_0.ntype end local concat, insert = table.concat, table.insert -local pos_to_line, get_line, get_closest_line, trim = util.pos_to_line, util.get_line, util.get_closest_line, util.trim +local pos_to_line, get_closest_line, trim = util.pos_to_line, util.get_closest_line, util.trim local mtype = util.moon.type local Line, Lines Lines = (function() @@ -254,7 +254,6 @@ Line = (function() return _class_0 end)() Block = (function() - local block_iterator local _parent_0 = nil local _base_0 = { header = "do", @@ -477,7 +476,6 @@ Block = (function() return end node = self.transform.statement(node) - local before = #self._lines local result do local fn = line_compile[ntype(node)] @@ -577,18 +575,6 @@ Block = (function() end }) _base_0.__class = _class_0 - local self = _class_0 - block_iterator = function(list) - return coroutine.wrap(function() - local _list_0 = list - for _index_0 = 1, #_list_0 do - local item = _list_0[_index_0] - if Block == mtype(item) then - coroutine.yield(item) - end - end - end) - end if _parent_0 and _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end diff --git a/moonscript/compile.moon b/moonscript/compile.moon index 6538c97c..70d3df41 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -14,7 +14,7 @@ import Set from require "moonscript.data" import ntype from require "moonscript.types" import concat, insert from table -import pos_to_line, get_line, get_closest_line, trim from util +import pos_to_line, get_closest_line, trim from util mtype = util.moon.type @@ -82,7 +82,6 @@ class Lines else t - -- copy with only array elements "Lines<#{util.dump(strip @)\sub 1, -2}>" -- Buffer for building up a line @@ -255,8 +254,6 @@ class Block buffer\add @header buffer\mark_pos @pos - -- print "Header:", util.dump(@header), mtype(@header).__name - if @next buffer\add @_lines @next\render buffer @@ -312,19 +309,10 @@ class Block with Line! \append_list [@value v for v in *values], delim - - block_iterator = (list) -> - coroutine.wrap -> - for item in *list - if Block == mtype item - coroutine.yield item - stm: (node, ...) => return if not node -- skip blank statements node = @transform.statement node - before = #@_lines - result = if fn = line_compile[ntype(node)] fn self, node, ... else From c4c3843537e24ef4813f1156f3196e77da5a4591 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 30 Oct 2012 09:11:06 -0700 Subject: [PATCH 006/554] don't crash when non-value is at end of loop expression --- moonscript/transform.lua | 14 +++++++++++++- moonscript/transform.moon | 9 ++++++++- tests/inputs/loops.moon | 9 +++++++++ tests/outputs/loops.lua | 28 ++++++++++++++++++++++++++++ 4 files changed, 58 insertions(+), 2 deletions(-) diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 2d28877c..6a40991a 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -1250,7 +1250,19 @@ Accumulator = (function() end else body = apply_to_last(body, function(n) - return build.assign_one(self.value_name, n) + if types.is_value(n) then + return build.assign_one(self.value_name, n) + else + return build.group({ + { + "declare", + { + self.value_name + } + }, + n + }) + end end) val = self.value_name end diff --git a/moonscript/transform.moon b/moonscript/transform.moon index ca295ff6..f99cead8 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -651,7 +651,14 @@ class Accumulator body = {} else body = apply_to_last body, (n) -> - build.assign_one @value_name, n + if types.is_value n + build.assign_one @value_name, n + else + -- just ignore it + build.group { + {"declare", {@value_name}} + n + } @value_name update = { diff --git a/tests/inputs/loops.moon b/tests/inputs/loops.moon index c8274707..6d37a82e 100644 --- a/tests/inputs/loops.moon +++ b/tests/inputs/loops.moon @@ -74,6 +74,15 @@ i = 0 x = while i < 10 i += 1 +-- values that can'e be coerced + +x = for thing in *3 + y = "hello" + +x = for x=1,2 + y = "hello" + + -- continue while true diff --git a/tests/outputs/loops.lua b/tests/outputs/loops.lua index 18b70e6f..eff6447e 100644 --- a/tests/outputs/loops.lua +++ b/tests/outputs/loops.lua @@ -143,6 +143,34 @@ x = (function() end return _accum_0 end)() +x = (function() + local _accum_0 = { } + local _len_0 = 0 + local _list_1 = 3 + for _index_0 = 1, #_list_1 do + local thing = _list_1[_index_0] + local _value_0 + y = "hello" + if _value_0 ~= nil then + _len_0 = _len_0 + 1 + _accum_0[_len_0] = _value_0 + end + end + return _accum_0 +end)() +x = (function() + local _accum_0 = { } + local _len_0 = 0 + for x = 1, 2 do + local _value_0 + y = "hello" + if _value_0 ~= nil then + _len_0 = _len_0 + 1 + _accum_0[_len_0] = _value_0 + end + end + return _accum_0 +end)() while true do local _continue_0 = false repeat From 19a8047618690cf2542d63965c83f09c5674f985 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 30 Oct 2012 09:25:23 -0700 Subject: [PATCH 007/554] clean out todo list --- todo | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/todo b/todo index 3b80bc66..07952e39 100644 --- a/todo +++ b/todo @@ -1,10 +1,5 @@ # TODO --- error when assining a loop whose body doesn't end in expression - -x = for x in y - y = 100 - -- seems like running in moon messes up require order - don't reuse _, put a local on it, so we don't keep around trash @@ -18,21 +13,13 @@ x = for x in y - error with stray comma at end of line - ugly error if attempting to assign to rvalue like #hello -- dump node in mark, see why values are being parsed multiple times - -- varargs that get put in a nested generated function aren't valid anymore: - - class expressions, x = class extends Hello do new: => print "hello" * multiline comments * table slices (almost) -* add continue keyword (ouch) * combine for and if line decorators -* elseif with value that inserts lines - - need to decompose elif into if inside else - * export later? x = 232 @@ -43,15 +30,9 @@ x = for x in y * any/every keywords for comprehensions? (what about iterators) -* let array items in table be defined without {} when indented - - -* allow dot access with names that are keywords: hello.then - -* convert tree transformer to be depth first instead of breadth first (lazy) - +* let array items in table be defined without {} when indented (no, too similar to arguments) --- for searching? +-- for searching? for returning to accumulator early? x = for thing in *things if is_important thing break thing From 1be72f57b7e36504fe470114f0d480a3d34c09bb Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 30 Oct 2012 09:38:47 -0700 Subject: [PATCH 008/554] add implicit return to end of files #46 --- moonscript/compile.lua | 14 +++++++++----- moonscript/compile.moon | 6 +++++- moonscript/transform.lua | 5 ++++- moonscript/transform.moon | 6 +++++- tests/outputs/class.lua | 2 +- tests/outputs/comprehension.lua | 2 +- tests/outputs/export.lua | 1 + tests/outputs/funcs.lua | 2 +- tests/outputs/lists.lua | 2 +- tests/outputs/literals.lua | 2 +- tests/outputs/string.lua | 2 +- tests/outputs/switch.lua | 2 +- tests/outputs/using.lua | 2 +- tests/outputs/whitespace.lua | 2 +- tests/outputs/with.lua | 1 + 15 files changed, 34 insertions(+), 17 deletions(-) diff --git a/moonscript/compile.lua b/moonscript/compile.lua index f9b1b811..6891c3c3 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -586,6 +586,14 @@ RootBlock = (function() __tostring = function(self) return "RootBlock<>" end, + root_stms = function(self, stms) + stms = transform.Statement.transformers.root_stms(self, stms) + local _list_0 = stms + for _index_0 = 1, #_list_0 do + local s = _list_0[_index_0] + self:stm(s) + end + end, render = function(self) local buffer = self._lines:flatten() if buffer[#buffer] == "\n" then @@ -652,11 +660,7 @@ tree = function(tree, scope) end assert(tree, "missing tree") local runner = coroutine.create(function() - local _list_0 = tree - for _index_0 = 1, #_list_0 do - local line = _list_0[_index_0] - scope:stm(line) - end + return scope:root_stms(tree) end) local success, err = coroutine.resume(runner) if not success then diff --git a/moonscript/compile.moon b/moonscript/compile.moon index 70d3df41..c1aae945 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -346,6 +346,10 @@ class RootBlock extends Block __tostring: => "RootBlock<>" + root_stms: (stms) => + stms = transform.Statement.transformers.root_stms self, stms + @stm s for s in *stms + render: => -- print @_lines buffer = @_lines\flatten! @@ -372,7 +376,7 @@ tree = (tree, scope=RootBlock!) -> assert tree, "missing tree" runner = coroutine.create -> - scope\stm line for line in *tree + scope\root_stms tree success, err = coroutine.resume runner if not success diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 6a40991a..82b3a5a0 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -5,6 +5,7 @@ local data = require("moonscript.data") local reversed = util.reversed local ntype, build, smart_node, is_slice, value_is_singular = types.ntype, types.build, types.smart_node, types.is_slice, types.value_is_singular local insert = table.insert +local implicitly_return LocalName = (function() local _parent_0 = nil local _base_0 = { @@ -443,6 +444,9 @@ construct_comprehension = function(inner, clauses) return current_stms[1] end Statement = Transformer({ + root_stms = function(self, body) + return apply_to_last(body, implicitly_return(self)) + end, assign = function(self, node) local names, values = unpack(node, 2) local transformed @@ -1329,7 +1333,6 @@ local default_accumulator default_accumulator = function(self, node) return Accumulator():convert(node) end -local implicitly_return implicitly_return = function(scope) local is_top = true local fn diff --git a/moonscript/transform.moon b/moonscript/transform.moon index f99cead8..c1c2b222 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -11,6 +11,8 @@ import insert from table export Statement, Value, NameProxy, LocalName, Run +local implicitly_return + -- always declares as local class LocalName new: (@name) => self[1] = "temp_name" @@ -186,6 +188,9 @@ construct_comprehension = (inner, clauses) -> current_stms[1] Statement = Transformer { + root_stms: (body) => + apply_to_last body, implicitly_return @ + assign: (node) => names, values = unpack node, 2 -- bubble cascading assigns @@ -679,7 +684,6 @@ class Accumulator default_accumulator = (node) => Accumulator!\convert node - implicitly_return = (scope) -> is_top = true fn = (stm) -> diff --git a/tests/outputs/class.lua b/tests/outputs/class.lua index 1f1aa4fd..5af14046 100644 --- a/tests/outputs/class.lua +++ b/tests/outputs/class.lua @@ -589,4 +589,4 @@ Whacko = (function() end return _class_0 end)() -print("hello") \ No newline at end of file +return print("hello") \ No newline at end of file diff --git a/tests/outputs/comprehension.lua b/tests/outputs/comprehension.lua index b1bf218d..b0ec9108 100644 --- a/tests/outputs/comprehension.lua +++ b/tests/outputs/comprehension.lua @@ -52,7 +52,7 @@ _ = (function() end return _tbl_0 end)() -_ = (function() +return (function() local _tbl_0 = { } local _list_0 = { { diff --git a/tests/outputs/export.lua b/tests/outputs/export.lua index 50e1328c..95a0238d 100644 --- a/tests/outputs/export.lua +++ b/tests/outputs/export.lua @@ -69,4 +69,5 @@ end do local _with_0 = tmp local j = 2000 + return _with_0 end \ No newline at end of file diff --git a/tests/outputs/funcs.lua b/tests/outputs/funcs.lua index 98a3f5f6..35dee928 100644 --- a/tests/outputs/funcs.lua +++ b/tests/outputs/funcs.lua @@ -108,7 +108,7 @@ k(function() return end end) -_ = function() +return function() if something then return real_name end diff --git a/tests/outputs/lists.lua b/tests/outputs/lists.lua index acc09ba8..87936ca8 100644 --- a/tests/outputs/lists.lua +++ b/tests/outputs/lists.lua @@ -286,7 +286,7 @@ _ = function() _ = x end end -_ = function() +return function() return (function() local _accum_0 = { } local _len_0 = 0 diff --git a/tests/outputs/literals.lua b/tests/outputs/literals.lua index 0f78e4cb..69609c5a 100644 --- a/tests/outputs/literals.lua +++ b/tests/outputs/literals.lua @@ -11,4 +11,4 @@ _ = [[ hello world ]] _ = [=[ hello world ]=] _ = [====[ hello world ]====] _ = "another world" -_ = 'what world' \ No newline at end of file +return 'what world' \ No newline at end of file diff --git a/tests/outputs/string.lua b/tests/outputs/string.lua index 0d1f8d76..2d751d81 100644 --- a/tests/outputs/string.lua +++ b/tests/outputs/string.lua @@ -34,4 +34,4 @@ local _ = "hello" ("hello"):format().hello(1, 2, 3); ("hello"):format(1, 2, 3) something("hello"):world() -something(("hello"):world()) \ No newline at end of file +return something(("hello"):world()) \ No newline at end of file diff --git a/tests/outputs/switch.lua b/tests/outputs/switch.lua index 9b39d7bc..96cc1042 100644 --- a/tests/outputs/switch.lua +++ b/tests/outputs/switch.lua @@ -43,7 +43,7 @@ do end end fix(this) -call_func((function() +return call_func((function() local _exp_5 = something if 1 == _exp_5 then return "yes" diff --git a/tests/outputs/using.lua b/tests/outputs/using.lua index 2ab41016..6111d284 100644 --- a/tests/outputs/using.lua +++ b/tests/outputs/using.lua @@ -12,7 +12,7 @@ _ = function(a, b, c) a, b, c = 1, 2, 3 local world = 12321 end -_ = function(a, e, f) +return function(a, e, f) local b, c a, b, c = 1, 2, 3 hello = 12321 diff --git a/tests/outputs/whitespace.lua b/tests/outputs/whitespace.lua index bcc868b0..ce2d7920 100644 --- a/tests/outputs/whitespace.lua +++ b/tests/outputs/whitespace.lua @@ -72,5 +72,5 @@ if hello(1, 2, 3, world, world) then print("hello") end if hello(1, 2, 3, world, world) then - print("hello") + return print("hello") end \ No newline at end of file diff --git a/tests/outputs/with.lua b/tests/outputs/with.lua index a0af190e..7d9ee768 100644 --- a/tests/outputs/with.lua +++ b/tests/outputs/with.lua @@ -45,4 +45,5 @@ do local _ = _with_0:prop("something").hello _with_0.prop:send(one) _with_0.prop:send(one) + return _with_0 end \ No newline at end of file From f8925a46a6e5aa07451848df0c94e329cbf54f62 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 30 Oct 2012 09:44:02 -0700 Subject: [PATCH 009/554] classes can implicitly return #46 --- moonscript/transform.lua | 17 ++++++++++----- moonscript/transform.moon | 12 +++++----- moonscript/types.lua | 3 ++- moonscript/types.moon | 2 +- tests/inputs/class.moon | 3 +++ tests/outputs/class.lua | 46 ++++++++++++++++++++++++++++++++++++++- 6 files changed, 69 insertions(+), 14 deletions(-) diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 82b3a5a0..e6b5e476 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -877,7 +877,7 @@ Statement = Transformer({ if_stm }) end, - class = function(self, node) + class = function(self, node, ret) local _, name, parent_val, body = unpack(node) local statements = { } local properties = { } @@ -1213,7 +1213,12 @@ Statement = Transformer({ values = { _with_0.block_exp(out_body) } - }) + }), + (function() + if ret then + return ret(name) + end + end)() }) end return value @@ -1342,15 +1347,15 @@ implicitly_return = function(scope) stm = scope.transform.statement(stm) t = ntype(stm) end - if types.manual_return[t] or not types.is_value(stm) then + if types.cascading[t] then + is_top = false + return scope.transform.statement(stm, fn) + elseif types.manual_return[t] or not types.is_value(stm) then if is_top and t == "return" and stm[2] == "" then return nil else return stm end - elseif types.cascading[t] then - is_top = false - return scope.transform.statement(stm, fn) else if t == "comprehension" and not types.comprehension_has_value(stm) then return stm diff --git a/moonscript/transform.moon b/moonscript/transform.moon index c1c2b222..9ab30883 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -439,7 +439,7 @@ Statement = Transformer { if_stm } - class: (node) => + class: (node, ret) => _, name, parent_val, body = unpack node -- split apart properties and statements @@ -620,6 +620,8 @@ Statement = Transformer { names: {name} values: {.block_exp out_body} } + if ret + ret name } value @@ -694,15 +696,15 @@ implicitly_return = (scope) -> stm = scope.transform.statement stm t = ntype stm - if types.manual_return[t] or not types.is_value stm + if types.cascading[t] + is_top = false + scope.transform.statement stm, fn + elseif types.manual_return[t] or not types.is_value stm -- remove blank return statement if is_top and t == "return" and stm[2] == "" nil else stm - elseif types.cascading[t] - is_top = false - scope.transform.statement stm, fn else if t == "comprehension" and not types.comprehension_has_value stm stm diff --git a/moonscript/types.lua b/moonscript/types.lua index fc5ec01f..4b917bf1 100644 --- a/moonscript/types.lua +++ b/moonscript/types.lua @@ -12,7 +12,8 @@ cascading = data.Set({ "if", "unless", "with", - "switch" + "switch", + "class" }) is_value = function(stm) local compile, transform = moonscript.compile, moonscript.transform diff --git a/moonscript/types.moon b/moonscript/types.moon index d072adb4..70cb1353 100644 --- a/moonscript/types.moon +++ b/moonscript/types.moon @@ -14,7 +14,7 @@ manual_return = data.Set{"foreach", "for", "while", "return"} -- Assigns and returns are bubbled into their bodies. -- All cascading statement transform functions accept a second arugment that -- is the transformation to apply to the last statement in their body -cascading = data.Set{ "if", "unless", "with", "switch" } +cascading = data.Set{ "if", "unless", "with", "switch", "class" } is_value = (stm) -> import compile, transform from moonscript diff --git a/tests/inputs/class.moon b/tests/inputs/class.moon index 92f6e6a5..16774681 100644 --- a/tests/inputs/class.moon +++ b/tests/inputs/class.moon @@ -129,4 +129,7 @@ class Whacko print "hello" +yyy = -> + class Cool + nil diff --git a/tests/outputs/class.lua b/tests/outputs/class.lua index 5af14046..2f32e382 100644 --- a/tests/outputs/class.lua +++ b/tests/outputs/class.lua @@ -589,4 +589,48 @@ Whacko = (function() end return _class_0 end)() -return print("hello") \ No newline at end of file +print("hello") +local yyy +yyy = function() + local Cool + Cool = (function() + local _parent_0 = nil + local _base_0 = { } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, ...) + if _parent_0 then + return _parent_0.__init(self, ...) + end + end, + __base = _base_0, + __name = "Cool", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + _ = nil + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + return _class_0 + end)() + return Cool +end \ No newline at end of file From bb633546be987bb8a2a43b027f34ec8736fa6243 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 30 Oct 2012 10:28:04 -0700 Subject: [PATCH 010/554] rebuild --- moon/all.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/moon/all.lua b/moon/all.lua index 3857b0c0..fd23b7e9 100644 --- a/moon/all.lua +++ b/moon/all.lua @@ -1,3 +1,3 @@ moon = moon or { } moon.inject = true -require("moon.init") +return require("moon.init") From 15dab06d31c0705d679e1f764f6c73f9285cd2f7 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 30 Oct 2012 20:23:36 -0700 Subject: [PATCH 011/554] add options to load functions, fix stacktrace for files run in moon also don't show nothing if rewriting stacktrace fails --- bin/moon | 21 +++++++++++++++------ moonscript/compile.lua | 16 ++++++++++------ moonscript/compile.moon | 11 +++++++---- moonscript/errors.lua | 5 ++++- moonscript/errors.moon | 5 ++++- moonscript/init.lua | 23 ++++++++++++++++------- moonscript/init.moon | 14 +++++++------- 7 files changed, 63 insertions(+), 32 deletions(-) diff --git a/bin/moon b/bin/moon index e5b3119a..5665a809 100755 --- a/bin/moon +++ b/bin/moon @@ -17,7 +17,7 @@ local help = [=[Usage: %s [options] [script [args]] ]=] local function print_err(...) - msg = table.concat({...}, "\t") + local msg = table.concat({...}, "\t") io.stderr:write(msg .. "\n") end @@ -49,7 +49,7 @@ local new_arg = { local moonscript_chunk, lua_parse_error local passed, err = pcall(function() - moonscript_chunk, lua_parse_error = moonscript.loadfile(script_fname) + moonscript_chunk, lua_parse_error = moonscript.loadfile(script_fname, { implicitly_return_root = false }) end) if not passed then @@ -70,16 +70,25 @@ getfenv(moonscript_chunk).arg = new_arg if not opts.d then local err, trace + xpcall(function() moonscript_chunk(unpack(new_arg)) end, function(_err) err = _err trace = debug.traceback("", 2) end) if err then - local traceback = util.trim(trace) - traceback = moonscript.errors.truncate_traceback(traceback) - print_err(moonscript.errors.rewrite_traceback(traceback, err)) - os.exit(1) + local truncated = moonscript.errors.truncate_traceback(util.trim(trace)) + local rewritten = moonscript.errors.rewrite_traceback(truncated, err) + + if rewritten then + print_err(rewritten) + else + -- faield to rewrite, show original + print_err(table.concat({ + err, + util.trim(trace) + }, "\n")) + end end else moonscript_chunk(unpack(new_arg)) diff --git a/moonscript/compile.lua b/moonscript/compile.lua index 6891c3c3..35a13216 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -587,7 +587,9 @@ RootBlock = (function() return "RootBlock<>" end, root_stms = function(self, stms) - stms = transform.Statement.transformers.root_stms(self, stms) + if not (self.options.implicitly_return_root == false) then + stms = transform.Statement.transformers.root_stms(self, stms) + end local _list_0 = stms for _index_0 = 1, #_list_0 do local s = _list_0[_index_0] @@ -607,9 +609,10 @@ RootBlock = (function() setmetatable(_base_0, _parent_0.__base) end local _class_0 = setmetatable({ - __init = function(self, ...) + __init = function(self, options) + self.options = options self.root = self - return _parent_0.__init(self, ...) + return _parent_0.__init(self) end, __base = _base_0, __name = "RootBlock", @@ -654,11 +657,12 @@ value = function(value) end return out end -tree = function(tree, scope) - if scope == nil then - scope = RootBlock() +tree = function(tree, options) + if options == nil then + options = { } end assert(tree, "missing tree") + local scope = (options.scope or RootBlock)(options) local runner = coroutine.create(function() return scope:root_stms(tree) end) diff --git a/moonscript/compile.moon b/moonscript/compile.moon index c1aae945..411ee9f4 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -340,14 +340,15 @@ class Block @stms fn lines class RootBlock extends Block - new: (...) => + new: (@options) => @root = self - super ... + super! __tostring: => "RootBlock<>" root_stms: (stms) => - stms = transform.Statement.transformers.root_stms self, stms + unless @options.implicitly_return_root == false + stms = transform.Statement.transformers.root_stms self, stms @stm s for s in *stms render: => @@ -372,9 +373,11 @@ value = (value) -> out = \render! out -tree = (tree, scope=RootBlock!) -> +tree = (tree, options={}) -> assert tree, "missing tree" + scope = (options.scope or RootBlock) options + runner = coroutine.create -> scope\root_stms tree diff --git a/moonscript/errors.lua b/moonscript/errors.lua index 08c65e2c..d895e50c 100644 --- a/moonscript/errors.lua +++ b/moonscript/errors.lua @@ -85,11 +85,14 @@ rewrite_traceback = function(text, err) end err = rewrite_single(err) local match = g:match(text) + if not (match) then + return nil + end for i, trace in ipairs(match) do match[i] = rewrite_single(trace) end return concat({ - "moon:" .. err, + "moon: " .. err, header_text, "\t" .. concat(match, "\n\t") }, "\n") diff --git a/moonscript/errors.moon b/moonscript/errors.moon index 4b48021e..ede5fce1 100644 --- a/moonscript/errors.moon +++ b/moonscript/errors.moon @@ -71,11 +71,14 @@ rewrite_traceback = (text, err) -> err = rewrite_single err match = g\match text + + return nil unless match + for i, trace in ipairs match match[i] = rewrite_single trace concat { - "moon:" .. err + "moon: " .. err header_text "\t" .. concat match, "\n\t" }, "\n" diff --git a/moonscript/init.lua b/moonscript/init.lua index 51a1e047..e8952243 100644 --- a/moonscript/init.lua +++ b/moonscript/init.lua @@ -20,7 +20,10 @@ create_moonpath = function(package_path) end return concat(paths, ";") end -to_lua = function(text) +to_lua = function(text, options) + if options == nil then + options = { } + end if "string" ~= type(text) then local t = type(text) error("expecting string (got " .. t .. ")", 2) @@ -29,7 +32,7 @@ to_lua = function(text) if not tree then error(err, 2) end - local code, ltable, pos = compile.tree(tree) + local code, ltable, pos = compile.tree(tree, options) if not code then error(compile.format_error(ltable, pos, text), 2) end @@ -65,9 +68,12 @@ end if not _G.moon_no_loader then init_loader() end -loadstring = function(str, chunk_name) +loadstring = function(str, chunk_name, options) + if options == nil then + options = nil + end local passed, code, ltable = pcall(function() - return to_lua(str) + return to_lua(str, options) end) if not passed then error(chunk_name .. ": " .. code, 2) @@ -77,16 +83,19 @@ loadstring = function(str, chunk_name) end return lua.loadstring(code, chunk_name or "=(moonscript.loadstring)") end -loadfile = function(fname) +loadfile = function(fname, options) + if options == nil then + options = nil + end local file, err = io.open(fname) if not file then return nil, err end local text = assert(file:read("*a")) file:close() - return loadstring(text, fname) + return loadstring(text, fname, options) end -dofile = function(fname) +dofile = function(fname, options) local f = assert(loadfile(fname)) return f() end diff --git a/moonscript/init.moon b/moonscript/init.moon index b0593870..61f15f8b 100644 --- a/moonscript/init.moon +++ b/moonscript/init.moon @@ -24,7 +24,7 @@ create_moonpath = (package_path) -> if p then paths[i] = p..".moon" concat paths, ";" -to_lua = (text) -> +to_lua = (text, options={}) -> if "string" != type text t = type text error "expecting string (got ".. t ..")", 2 @@ -33,7 +33,7 @@ to_lua = (text) -> if not tree error err, 2 - code, ltable, pos = compile.tree tree + code, ltable, pos = compile.tree tree, options if not code error compile.format_error(ltable, pos, text), 2 @@ -63,23 +63,23 @@ init_loader = -> init_loader! if not _G.moon_no_loader -loadstring = (str, chunk_name) -> - passed, code, ltable = pcall -> to_lua str +loadstring = (str, chunk_name, options=nil) -> + passed, code, ltable = pcall -> to_lua str, options if not passed error chunk_name .. ": " .. code, 2 line_tables[chunk_name] = ltable if chunk_name lua.loadstring code, chunk_name or "=(moonscript.loadstring)" -loadfile = (fname) -> +loadfile = (fname, options=nil) -> file, err = io.open fname return nil, err if not file text = assert file\read "*a" file\close! - loadstring text, fname + loadstring text, fname, options -- throws errros -dofile = (fname) -> +dofile = (fname, options) -> f = assert loadfile fname f! From b6987fe6d8be28eeeda725bba1147fa06d715a5c Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 30 Oct 2012 23:34:42 -0700 Subject: [PATCH 012/554] wrap class declaration in do instead of anonymous function --- moonscript/compile.lua | 24 +++++------ moonscript/data.lua | 6 +-- moonscript/transform.lua | 41 ++++++++----------- moonscript/transform.moon | 8 ++-- tests/outputs/class.lua | 84 +++++++++++++++++++-------------------- tests/outputs/export.lua | 6 +-- 6 files changed, 80 insertions(+), 89 deletions(-) diff --git a/moonscript/compile.lua b/moonscript/compile.lua index 35a13216..0e200d8f 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -20,7 +20,7 @@ local concat, insert = table.concat, table.insert local pos_to_line, get_closest_line, trim = util.pos_to_line, util.get_closest_line, util.trim local mtype = util.moon.type local Line, Lines -Lines = (function() +do local _parent_0 = nil local _base_0 = { mark_pos = function(self, pos, line) @@ -143,9 +143,9 @@ Lines = (function() if _parent_0 and _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end - return _class_0 -end)() -Line = (function() + Lines = _class_0 +end +do local _parent_0 = nil local _base_0 = { pos = nil, @@ -251,9 +251,9 @@ Line = (function() if _parent_0 and _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end - return _class_0 -end)() -Block = (function() + Line = _class_0 +end +do local _parent_0 = nil local _base_0 = { header = "do", @@ -578,9 +578,9 @@ Block = (function() if _parent_0 and _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end - return _class_0 -end)() -RootBlock = (function() + Block = _class_0 +end +do local _parent_0 = Block local _base_0 = { __tostring = function(self) @@ -636,8 +636,8 @@ RootBlock = (function() if _parent_0 and _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end - return _class_0 -end)() + RootBlock = _class_0 +end format_error = function(msg, pos, file_str) local line = pos_to_line(file_str, pos) local line_str diff --git a/moonscript/data.lua b/moonscript/data.lua index 81fc3c7d..be0bcfe9 100644 --- a/moonscript/data.lua +++ b/moonscript/data.lua @@ -9,7 +9,7 @@ Set = function(items) end return self end -Stack = (function() +do local _parent_0 = nil local _base_0 = { __tostring = function(self) @@ -63,8 +63,8 @@ Stack = (function() if _parent_0 and _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end - return _class_0 -end)() + Stack = _class_0 +end lua_keywords = Set({ 'and', 'break', diff --git a/moonscript/transform.lua b/moonscript/transform.lua index e6b5e476..88421969 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -6,7 +6,7 @@ local reversed = util.reversed local ntype, build, smart_node, is_slice, value_is_singular = types.ntype, types.build, types.smart_node, types.is_slice, types.value_is_singular local insert = table.insert local implicitly_return -LocalName = (function() +do local _parent_0 = nil local _base_0 = { get_name = function(self) @@ -44,9 +44,9 @@ LocalName = (function() if _parent_0 and _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end - return _class_0 -end)() -NameProxy = (function() + LocalName = _class_0 +end +do local _parent_0 = nil local _base_0 = { get_name = function(self, scope) @@ -134,9 +134,9 @@ NameProxy = (function() if _parent_0 and _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end - return _class_0 -end)() -Run = (function() + NameProxy = _class_0 +end +do local _parent_0 = nil local _base_0 = { call = function(self, state) @@ -174,8 +174,8 @@ Run = (function() if _parent_0 and _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end - return _class_0 -end)() + Run = _class_0 +end local apply_to_last apply_to_last = function(stms, fn) local last_exp_id = 0 @@ -340,7 +340,7 @@ with_continue_listener = function(body) } end local Transformer -Transformer = (function() +do local _parent_0 = nil local _base_0 = { transform = function(self, scope, node, ...) @@ -408,8 +408,8 @@ Transformer = (function() if _parent_0 and _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end - return _class_0 -end)() + Transformer = _class_0 +end local construct_comprehension construct_comprehension = function(inner, clauses) local current_stms = inner @@ -1197,7 +1197,7 @@ Statement = Transformer({ }) } }), - cls_name + _with_0.assign_one(name, cls_name) } hoist_declarations(out_body) value = _with_0.group({ @@ -1206,14 +1206,7 @@ Statement = Transformer({ name } }), - _with_0.assign({ - names = { - name - }, - values = { - _with_0.block_exp(out_body) - } - }), + _with_0["do"](out_body), (function() if ret then return ret(name) @@ -1225,7 +1218,7 @@ Statement = Transformer({ end }) local Accumulator -Accumulator = (function() +do local _parent_0 = nil local _base_0 = { body_idx = { @@ -1332,8 +1325,8 @@ Accumulator = (function() if _parent_0 and _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end - return _class_0 -end)() + Accumulator = _class_0 +end local default_accumulator default_accumulator = function(self, node) return Accumulator():convert(node) diff --git a/moonscript/transform.moon b/moonscript/transform.moon index 9ab30883..21168c73 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -609,17 +609,15 @@ Statement = Transformer { } } - cls_name + .assign_one name, cls_name } hoist_declarations out_body value = .group { .declare names: {name} - .assign { - names: {name} - values: {.block_exp out_body} - } + .do out_body + if ret ret name } diff --git a/tests/outputs/class.lua b/tests/outputs/class.lua index 2f32e382..efadb79d 100644 --- a/tests/outputs/class.lua +++ b/tests/outputs/class.lua @@ -1,5 +1,5 @@ local Hello -Hello = (function() +do local _parent_0 = nil local _base_0 = { hello = function(self) @@ -40,13 +40,13 @@ Hello = (function() if _parent_0 and _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end - return _class_0 -end)() + Hello = _class_0 +end local x = Hello(1, 2) x:hello() print(x) local Simple -Simple = (function() +do local _parent_0 = nil local _base_0 = { cool = function(self) @@ -85,10 +85,10 @@ Simple = (function() if _parent_0 and _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end - return _class_0 -end)() + Simple = _class_0 +end local Yikes -Yikes = (function() +do local _parent_0 = Simple local _base_0 = { } _base_0.__index = _base_0 @@ -121,12 +121,12 @@ Yikes = (function() if _parent_0 and _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end - return _class_0 -end)() + Yikes = _class_0 +end x = Yikes() x:cool() local Hi -Hi = (function() +do local _parent_0 = nil local _base_0 = { cool = function(self, num) @@ -163,9 +163,9 @@ Hi = (function() if _parent_0 and _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end - return _class_0 -end)() -Simple = (function() + Hi = _class_0 +end +do local _parent_0 = Hi local _base_0 = { cool = function(self) @@ -202,13 +202,13 @@ Simple = (function() if _parent_0 and _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end - return _class_0 -end)() + Simple = _class_0 +end x = Simple() x:cool() print(x.__class == Simple) local Okay -Okay = (function() +do local _parent_0 = nil local _base_0 = { something = 20323 @@ -245,10 +245,10 @@ Okay = (function() if _parent_0 and _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end - return _class_0 -end)() + Okay = _class_0 +end local Biggie -Biggie = (function() +do local _parent_0 = Okay local _base_0 = { something = function(self) @@ -289,10 +289,10 @@ Biggie = (function() if _parent_0 and _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end - return _class_0 -end)() + Biggie = _class_0 +end local Yeah -Yeah = (function() +do local _parent_0 = nil local _base_0 = { okay = function(self) @@ -331,10 +331,10 @@ Yeah = (function() if _parent_0 and _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end - return _class_0 -end)() + Yeah = _class_0 +end local What -What = (function() +do local _parent_0 = nil local _base_0 = { something = function(self) @@ -373,9 +373,9 @@ What = (function() if _parent_0 and _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end - return _class_0 -end)() -Hello = (function() + What = _class_0 +end +do local _parent_0 = What local _base_0 = { val = 2323, @@ -421,8 +421,8 @@ Hello = (function() if _parent_0 and _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end - return _class_0 -end)() + Hello = _class_0 +end do local _with_0 = Hello() x = _with_0:something() @@ -430,7 +430,7 @@ do x() end local CoolSuper -CoolSuper = (function() +do local _parent_0 = nil local _base_0 = { hi = function(self) @@ -475,8 +475,8 @@ CoolSuper = (function() if _parent_0 and _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end - return _class_0 -end)() + CoolSuper = _class_0 +end x = self.hello x = self.__class.hello self:hello("world") @@ -487,7 +487,7 @@ xx = function(hello, world, cool) self.hello, self.__class.world = hello, world end local ClassMan -ClassMan = (function() +do local _parent_0 = nil local _base_0 = { blue = function(self) end, @@ -530,8 +530,8 @@ ClassMan = (function() if _parent_0 and _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end - return _class_0 -end)() + ClassMan = _class_0 +end x = self local y = self.__class self(something) @@ -541,7 +541,7 @@ self = 343 self.hello(2, 3, 4) local _ = hello[self].world local Whacko -Whacko = (function() +do local hello local _parent_0 = nil local _base_0 = { } @@ -587,13 +587,13 @@ Whacko = (function() if _parent_0 and _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end - return _class_0 -end)() + Whacko = _class_0 +end print("hello") local yyy yyy = function() local Cool - Cool = (function() + do local _parent_0 = nil local _base_0 = { } _base_0.__index = _base_0 @@ -630,7 +630,7 @@ yyy = function() if _parent_0 and _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end - return _class_0 - end)() + Cool = _class_0 + end return Cool end \ No newline at end of file diff --git a/tests/outputs/export.lua b/tests/outputs/export.lua index 95a0238d..a609aea4 100644 --- a/tests/outputs/export.lua +++ b/tests/outputs/export.lua @@ -1,6 +1,6 @@ a, b, c = 223, 343 cool = "dad" -Something = (function() +do local _parent_0 = nil local _base_0 = { umm = "cool" @@ -37,8 +37,8 @@ Something = (function() if _parent_0 and _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end - return _class_0 -end)() + Something = _class_0 +end local What if this then What = 232 From 021d4878a0df427f5a87f17530cc1778a44bcb48 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 31 Oct 2012 00:07:59 -0700 Subject: [PATCH 013/554] class name can be any assignable expression #46 --- moonscript/parse.lua | 2 +- moonscript/transform.lua | 52 +++++++++++----- moonscript/transform.moon | 23 +++++-- tests/inputs/class.moon | 14 +++++ tests/outputs/class.lua | 122 +++++++++++++++++++++++++++++++++++++- 5 files changed, 191 insertions(+), 22 deletions(-) diff --git a/moonscript/parse.lua b/moonscript/parse.lua index f736f630..75987376 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -507,7 +507,7 @@ local build_grammar = wrap_env(function() TableBlockInner = Ct(KeyValueLine * (SpaceBreak^1 * KeyValueLine)^0), TableBlock = SpaceBreak^1 * Advance * ensure(TableBlockInner, PopIndent) / mark"table", - ClassDecl = key"class" * Name * (key"extends" * PreventIndent * ensure(Exp, PopIndent) + C"")^-1 * ClassBlock / mark"class", + ClassDecl = key"class" * Assignable * (key"extends" * PreventIndent * ensure(Exp, PopIndent) + C"")^-1 * ClassBlock / mark"class", ClassBlock = SpaceBreak^1 * Advance * Ct(ClassLine * (SpaceBreak^1 * ClassLine)^0) * PopIndent, diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 88421969..e055c479 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -954,6 +954,28 @@ Statement = Transformer({ smart_node(constructor) constructor.arrow = "fat" end + local real_name + if ntype(name) == "chain" then + local last = name[#name] + local _exp_0 = ntype(last) + if "dot" == _exp_0 then + real_name = { + "string", + '"', + last[2] + } + elseif "index" == _exp_0 then + real_name = last[2] + else + real_name = "nil" + end + else + real_name = { + "string", + '"', + name + } + end local cls = build.table({ { "__init", @@ -965,11 +987,7 @@ Statement = Transformer({ }, { "__name", - { - "string", - '"', - name - } + real_name }, { "__parent", @@ -1197,21 +1215,25 @@ Statement = Transformer({ }) } }), - _with_0.assign_one(name, cls_name) + _with_0.assign_one(name, cls_name), + (function() + if ret then + return ret(cls_name) + end + end)() } hoist_declarations(out_body) value = _with_0.group({ - _with_0.declare({ - names = { - name - } - }), - _with_0["do"](out_body), (function() - if ret then - return ret(name) + if ntype(name) == "value" then + return _with_0.declare({ + names = { + name + } + }) end - end)() + end)(), + _with_0["do"](out_body) }) end return value diff --git a/moonscript/transform.moon b/moonscript/transform.moon index 21168c73..5e27aaa4 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -488,10 +488,22 @@ Statement = Transformer { smart_node constructor constructor.arrow = "fat" + real_name = if ntype(name) == "chain" + last = name[#name] + switch ntype last + when "dot" + {"string", '"', last[2]} + when "index" + last[2] + else + "nil" + else + {"string", '"', name} + cls = build.table { {"__init", constructor} {"__base", base_name} - {"__name", {"string", '"', name}} -- "quote the string" + {"__name", real_name} -- "quote the string" {"__parent", parent_cls_name} } @@ -610,16 +622,17 @@ Statement = Transformer { } .assign_one name, cls_name + if ret + ret cls_name } hoist_declarations out_body value = .group { - .declare names: {name} - .do out_body + if ntype(name) == "value" + .declare names: {name} - if ret - ret name + .do out_body } value diff --git a/tests/inputs/class.moon b/tests/inputs/class.moon index 16774681..4b2e48cf 100644 --- a/tests/inputs/class.moon +++ b/tests/inputs/class.moon @@ -133,3 +133,17 @@ yyy = -> class Cool nil + +-- + +class a.b.c.D + nil + + +class a.b["hello"] + nil + +class (-> require "moon")!.Something extends Hello.World + nil + + diff --git a/tests/outputs/class.lua b/tests/outputs/class.lua index efadb79d..18eb968f 100644 --- a/tests/outputs/class.lua +++ b/tests/outputs/class.lua @@ -631,6 +631,126 @@ yyy = function() _parent_0.__inherited(_parent_0, _class_0) end Cool = _class_0 + return _class_0 end - return Cool +end +do + local _parent_0 = nil + local _base_0 = { } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, ...) + if _parent_0 then + return _parent_0.__init(self, ...) + end + end, + __base = _base_0, + __name = "D", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + _ = nil + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + a.b.c.D = _class_0 +end +do + local _parent_0 = nil + local _base_0 = { } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, ...) + if _parent_0 then + return _parent_0.__init(self, ...) + end + end, + __base = _base_0, + __name = "hello", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + _ = nil + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + a.b["hello"] = _class_0 +end +do + local _parent_0 = Hello.World + local _base_0 = { } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, ...) + if _parent_0 then + return _parent_0.__init(self, ...) + end + end, + __base = _base_0, + __name = "Something", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + _ = nil + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + (function() + return require("moon") + end)().Something = _class_0 + return _class_0 end \ No newline at end of file From 5b9e1a438988f992dbc090a8059d909b4dcd8a2e Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 31 Oct 2012 00:43:26 -0700 Subject: [PATCH 014/554] better error when assigning invalid left hand side, fixes #36 --- moonscript/parse.lua | 46 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 75987376..fc6fa3ac 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -166,10 +166,15 @@ end -- makes sure the last item in a chain is an index local _assignable = { index = true, dot = true, slice = true } + +local function is_assignable(node) + local t = ntype(node) + return t == "self" or t == "value" or + t == "chain" and _assignable[ntype(node[#node])] +end + local function check_assignable(str, pos, value) - if ntype(value) == "chain" and _assignable[ntype(value[#value])] - or type(value) == "string" - then + if is_assignable(value) then return true, value end return false @@ -181,6 +186,13 @@ local function format_assign(lhs_exps, assign) return flatten_explist(lhs_exps) end + for _, assign_exp in ipairs(lhs_exps) do + if not is_assignable(assign_exp) then + print(util.dump(assign_exp)) + error {assign_exp, "left hand expression is not assignable"} + end + end + local t = ntype(assign) if t == "assign" then return {"assign", lhs_exps, unpack(assign, 2)} @@ -276,7 +288,7 @@ local function self_assign(name) return {{"key_literal", name}, name} end -local err_msg = "Failed to parse:\n [%d] >> %s (%d)" +local err_msg = "Failed to parse:%s\n [%d] >> %s" local build_grammar = wrap_env(function() local _indent = Stack(0) -- current indent @@ -559,16 +571,30 @@ local build_grammar = wrap_env(function() end local tree - local args = {...} - local pass, err = assert(pcall(function() - tree = self._g:match(str, unpack(args)) - end)) + local pass, err = pcall(function(...) + tree = self._g:match(str, ...) + end, ...) + + -- regular error, let it bubble up + if type(err) == "string" then + error(err) + end if not tree then - local line_no = pos_to_line(last_pos) + local pos = last_pos + local msg + + if err then + local node + node, msg = unpack(err) + msg = msg and " " .. msg + pos = node[-1] + end + + local line_no = pos_to_line(pos) local line_str = get_line(line_no) or "" - return nil, err_msg:format(line_no, trim(line_str), _indent:top()) + return nil, err_msg:format(msg or "", line_no, trim(line_str)) end return tree end From 32a2c52eec07d2501723c2bfd6fd6f09669b999d Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 31 Oct 2012 09:57:07 -0700 Subject: [PATCH 015/554] fix error for when test isn't build --- test2.moon | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test2.moon b/test2.moon index 499837e3..fb65cb8e 100644 --- a/test2.moon +++ b/test2.moon @@ -43,9 +43,9 @@ benchmark = (fn) -> nil, fn! read_all = (fname) -> - f = io.open(fname, "r") - with f\read "*a" - f\close! + if f = io.open(fname, "r") + with f\read "*a" + f\close! diff_file = (a_fname, b_fname) -> out = io.popen(options.diff.tool .. " ".. a_fname .. " " .. b_fname, "r")\read "*a" @@ -107,7 +107,7 @@ describe "input tests", -> \close! else expected_str = read_all output_fname name - return "Test not built: " .. input_fname(name) unless expected_str + error "Test not built: " .. input_fname(name) unless expected_str string_assert expected_str, code From 67584ec9f7f237573ecf163fa74a6317a6416bc7 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 31 Oct 2012 09:59:36 -0700 Subject: [PATCH 016/554] add support for do block, close #30 --- moonscript/parse.lua | 40 +++++++++++++++++++++++++++++++++++---- moonscript/transform.lua | 3 +++ moonscript/transform.moon | 3 +++ moonscript/types.lua | 3 ++- moonscript/types.moon | 2 +- 5 files changed, 45 insertions(+), 6 deletions(-) diff --git a/moonscript/parse.lua b/moonscript/parse.lua index fc6fa3ac..e73a0597 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -292,6 +292,7 @@ local err_msg = "Failed to parse:%s\n [%d] >> %s" local build_grammar = wrap_env(function() local _indent = Stack(0) -- current indent + local _do_stack = Stack(0) local last_pos = 0 -- used to know where to report error local function check_indent(str, pos, indent) @@ -317,6 +318,34 @@ local build_grammar = wrap_env(function() return true end + + local function check_do(str, pos, do_node) + local top = _do_stack:top() + if top == nil or top then + return true, do_node + end + return false + end + + local function disable_do(str_pos) + _do_stack:push(false) + return true + end + + local function enable_do(str_pos) + _do_stack:push(true) + return true + end + + local function pop_do(str, pos) + if nil == _do_stack:pop() then error("unexpected do pop") end + return true + end + + local DisableDo = Cmt("", disable_do) + local EnableDo = Cmt("", enable_do) + local PopDo = Cmt("", pop_do) + local keywords = {} local function key(chars) keywords[chars] = true @@ -384,9 +413,9 @@ local build_grammar = wrap_env(function() Return = key"return" * (ExpListLow/mark"explist" + C"") / mark"return", - With = key"with" * Exp * key"do"^-1 * Body / mark"with", + With = key"with" * DisableDo * ensure(Exp, PopDo) * key"do"^-1 * Body / mark"with", - Switch = key"switch" * Exp * key"do"^-1 * Space^-1 * Break * SwitchBlock / mark"switch", + Switch = key"switch" * DisableDo * ensure(Exp, PopDo) * key"do"^-1 * Space^-1 * Break * SwitchBlock / mark"switch", SwitchBlock = EmptyLine^0 * Advance * Ct(SwitchCase * (Break^1 * SwitchCase)^0 * (Break^1 * SwitchElse)^-1) * PopIndent, SwitchCase = key"when" * Exp * key"then"^-1 * Body / mark"case", @@ -401,13 +430,15 @@ local build_grammar = wrap_env(function() Unless = key"unless" * IfCond * key"then"^-1 * Body * ((Break * CheckIndent)^-1 * EmptyLine^0 * key"else" * Body / mark"else")^-1 / mark"unless", - While = key"while" * Exp * key"do"^-1 * Body / mark"while", + While = key"while" * DisableDo * ensure(Exp, PopDo) * key"do"^-1 * Body / mark"while", - For = key"for" * (Name * sym"=" * Ct(Exp * sym"," * Exp * (sym"," * Exp)^-1)) * + For = key"for" * DisableDo * ensure(Name * sym"=" * Ct(Exp * sym"," * Exp * (sym"," * Exp)^-1), PopDo) * key"do"^-1 * Body / mark"for", ForEach = key"for" * Ct(NameList) * key"in" * Ct(sym"*" * Exp / mark"unpack" + ExpList) * key"do"^-1 * Body / mark"foreach", + Do = key"do" * Body / mark"do", + Comprehension = sym"[" * Exp * CompInner * sym"]" / mark"comprehension", TblComprehension = sym"{" * Ct(Exp * (sym"," * Exp)^-1) * CompInner * sym"}" / mark"tblcomprehension", @@ -436,6 +467,7 @@ local build_grammar = wrap_env(function() Switch + With + ForEach + For + While + + Cmt(Do, check_do) + sym"-" * -SomeSpace * Exp / mark"minus" + sym"#" * Exp / mark"length" + key"not" * Exp / mark"not" + diff --git a/moonscript/transform.lua b/moonscript/transform.lua index e055c479..962a9f67 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -1388,6 +1388,9 @@ Value = Transformer({ ["for"] = default_accumulator, ["while"] = default_accumulator, foreach = default_accumulator, + ["do"] = function(self, node) + return build.block_exp(node[2]) + end, decorated = function(self, node) return self.transform.statement(node) end, diff --git a/moonscript/transform.moon b/moonscript/transform.moon index 5e27aaa4..a2b140a4 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -729,6 +729,9 @@ Value = Transformer { while: default_accumulator foreach: default_accumulator + do: (node) => + build.block_exp node[2] + decorated: (node) => @transform.statement node diff --git a/moonscript/types.lua b/moonscript/types.lua index 4b917bf1..9e12e0c7 100644 --- a/moonscript/types.lua +++ b/moonscript/types.lua @@ -13,7 +13,8 @@ cascading = data.Set({ "unless", "with", "switch", - "class" + "class", + "do" }) is_value = function(stm) local compile, transform = moonscript.compile, moonscript.transform diff --git a/moonscript/types.moon b/moonscript/types.moon index 70cb1353..c5e9ce05 100644 --- a/moonscript/types.moon +++ b/moonscript/types.moon @@ -14,7 +14,7 @@ manual_return = data.Set{"foreach", "for", "while", "return"} -- Assigns and returns are bubbled into their bodies. -- All cascading statement transform functions accept a second arugment that -- is the transformation to apply to the last statement in their body -cascading = data.Set{ "if", "unless", "with", "switch", "class" } +cascading = data.Set{ "if", "unless", "with", "switch", "class", "do" } is_value = (stm) -> import compile, transform from moonscript From abc2599d15dbcd6258ef4adba89c95435b05ef8e Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 31 Oct 2012 13:44:56 -0700 Subject: [PATCH 017/554] fix export ^ with class declarations inside of do --- moonscript/transform.lua | 10 ++++++++-- moonscript/transform.moon | 13 +++++++++++-- tests/inputs/class.moon | 8 ++++++++ tests/outputs/class.lua | 39 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 66 insertions(+), 4 deletions(-) diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 962a9f67..4cab6399 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -5,6 +5,7 @@ local data = require("moonscript.data") local reversed = util.reversed local ntype, build, smart_node, is_slice, value_is_singular = types.ntype, types.build, types.smart_node, types.is_slice, types.value_is_singular local insert = table.insert +local mtype = util.moon.type local implicitly_return do local _parent_0 = nil @@ -233,7 +234,7 @@ find_assigns = function(body, out) return out end local hoist_declarations -hoist_declarations = function(body, rules) +hoist_declarations = function(body) local assigns = { } local _list_0 = find_assigns(body) for _index_0 = 1, #_list_0 do @@ -246,7 +247,11 @@ hoist_declarations = function(body, rules) end end end - return table.insert(body, 1, { + local idx = 1 + while mtype(body[idx]) == Run do + idx = idx + 1 + end + return table.insert(body, idx, { "declare", assigns }) @@ -1092,6 +1097,7 @@ Statement = Transformer({ local _with_0 = build local out_body = { Run(function(self) + self:put_name(name) return self:set("super", function(block, chain) if chain then local slice = (function() diff --git a/moonscript/transform.moon b/moonscript/transform.moon index a2b140a4..374f4e28 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -9,6 +9,8 @@ import reversed from util import ntype, build, smart_node, is_slice, value_is_singular from types import insert from table +mtype = util.moon.type + export Statement, Value, NameProxy, LocalName, Run local implicitly_return @@ -92,7 +94,7 @@ find_assigns = (body, out={}) -> table.insert out, thing[2] -- extract names out -hoist_declarations = (body, rules) -> +hoist_declarations = (body) -> assigns = {} -- hoist the plain old assigns @@ -100,7 +102,11 @@ hoist_declarations = (body, rules) -> for name in *names table.insert assigns, name if type(name) == "string" - table.insert body, 1, {"declare", assigns} + -- insert after runs + idx = 1 + while mtype(body[idx]) == Run do idx += 1 + + table.insert body, idx, {"declare", assigns} expand_elseif_assign = (ifstm) -> for i = 4, #ifstm @@ -551,6 +557,9 @@ Statement = Transformer { with build out_body = { Run => + -- make sure we don't assign the class to a local inside the do + @put_name name + @set "super", (block, chain) -> if chain slice = [item for item in *chain[3,]] diff --git a/tests/inputs/class.moon b/tests/inputs/class.moon index 4b2e48cf..40c0957c 100644 --- a/tests/inputs/class.moon +++ b/tests/inputs/class.moon @@ -147,3 +147,11 @@ class (-> require "moon")!.Something extends Hello.World nil + +-- + +export ^ +class Something + nil + + diff --git a/tests/outputs/class.lua b/tests/outputs/class.lua index 18eb968f..4498f286 100644 --- a/tests/outputs/class.lua +++ b/tests/outputs/class.lua @@ -752,5 +752,44 @@ do (function() return require("moon") end)().Something = _class_0 +end +do + local _parent_0 = nil + local _base_0 = { } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, ...) + if _parent_0 then + return _parent_0.__init(self, ...) + end + end, + __base = _base_0, + __name = "Something", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + _ = nil + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Something = _class_0 return _class_0 end \ No newline at end of file From 6b56bc711c2b5c798d158d23a6c47e2fbddbcdd1 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 31 Oct 2012 13:47:56 -0700 Subject: [PATCH 018/554] left out DisableDo for foreach loop --- moonscript/parse.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/moonscript/parse.lua b/moonscript/parse.lua index e73a0597..7f86ab7c 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -435,7 +435,7 @@ local build_grammar = wrap_env(function() For = key"for" * DisableDo * ensure(Name * sym"=" * Ct(Exp * sym"," * Exp * (sym"," * Exp)^-1), PopDo) * key"do"^-1 * Body / mark"for", - ForEach = key"for" * Ct(NameList) * key"in" * Ct(sym"*" * Exp / mark"unpack" + ExpList) * key"do"^-1 * Body / mark"foreach", + ForEach = key"for" * Ct(NameList) * key"in" * DisableDo * ensure(Ct(sym"*" * Exp / mark"unpack" + ExpList), PopDo) * key"do"^-1 * Body / mark"foreach", Do = key"do" * Body / mark"do", From 05c3725b8e568b32ac87514e4a2ff9749720fadc Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 31 Oct 2012 14:16:21 -0700 Subject: [PATCH 019/554] making modules not vulnerable to accidental return --- moon/init.lua | 1 + moon/init.moon | 1 + moonscript/data.lua | 1 + moonscript/data.moon | 3 +++ moonscript/types.lua | 1 + moonscript/types.moon | 1 + moonscript/util.lua | 1 + moonscript/util.moon | 1 + 8 files changed, 10 insertions(+) diff --git a/moon/init.lua b/moon/init.lua index dbd9eb30..af6337a3 100644 --- a/moon/init.lua +++ b/moon/init.lua @@ -161,3 +161,4 @@ fold = function(items, fn) return items[1] end end +return nil diff --git a/moon/init.moon b/moon/init.moon index 33ee125e..f3d822e9 100644 --- a/moon/init.moon +++ b/moon/init.moon @@ -134,3 +134,4 @@ fold = (items, fn)-> else items[1] +nil diff --git a/moonscript/data.lua b/moonscript/data.lua index be0bcfe9..ac9f3f0b 100644 --- a/moonscript/data.lua +++ b/moonscript/data.lua @@ -88,3 +88,4 @@ lua_keywords = Set({ 'until', 'while' }) +return nil diff --git a/moonscript/data.moon b/moonscript/data.moon index 6b9050f5..8c18a84e 100644 --- a/moonscript/data.moon +++ b/moonscript/data.moon @@ -37,3 +37,6 @@ lua_keywords = Set{ 'until', 'while' } +nil + + diff --git a/moonscript/types.lua b/moonscript/types.lua index 9e12e0c7..4ec240e3 100644 --- a/moonscript/types.lua +++ b/moonscript/types.lua @@ -261,3 +261,4 @@ smart_node = function(node) end }) end +return nil diff --git a/moonscript/types.moon b/moonscript/types.moon index c5e9ce05..11a83dcd 100644 --- a/moonscript/types.moon +++ b/moonscript/types.moon @@ -149,3 +149,4 @@ smart_node = (node) -> rawset node, key, value } +nil diff --git a/moonscript/util.lua b/moonscript/util.lua index e9845e96..42531fa6 100644 --- a/moonscript/util.lua +++ b/moonscript/util.lua @@ -135,3 +135,4 @@ debug_posmap = function(posmap, moon_code, lua_code) end)() return concat(lines, "\n") end +return nil diff --git a/moonscript/util.moon b/moonscript/util.moon index 7bbb8c12..a7a9a765 100644 --- a/moonscript/util.moon +++ b/moonscript/util.moon @@ -90,4 +90,5 @@ debug_posmap = (posmap, moon_code, lua_code) -> concat(lines, "\n") +nil From c783eff2a4b7fd41bae6b98bbc4c27ba55c01878 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 31 Oct 2012 20:13:26 -0700 Subject: [PATCH 020/554] actually show errors in test2 --- test2.moon | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test2.moon b/test2.moon index fb65cb8e..40fecd73 100644 --- a/test2.moon +++ b/test2.moon @@ -95,9 +95,9 @@ describe "input tests", -> file_str = read_all input_fname name parse_time, tree, err = benchmark -> parse.string file_str - return err if err + error err if err compile_time, code, err, pos = benchmark -> compile.tree tree - return compile.format_error err, pos, file_str unless code + error compile.format_error err, pos, file_str unless code table.insert timings, {name, parse_time, compile_time} From 0d1f25c2defcc42cd7c51876108824e820fecd2c Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 31 Oct 2012 20:15:44 -0700 Subject: [PATCH 021/554] tests for do --- tests/inputs/do.moon | 27 +++++++++++++++++++++++++ tests/outputs/do.lua | 48 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 tests/inputs/do.moon create mode 100644 tests/outputs/do.lua diff --git a/tests/inputs/do.moon b/tests/inputs/do.moon new file mode 100644 index 00000000..334e68f3 --- /dev/null +++ b/tests/inputs/do.moon @@ -0,0 +1,27 @@ + +do + print "hello" + print "world" + +x = do + print "hello" + print "world" + +y = do + things = "shhh" + -> "hello: " .. things + +-> if something then do "yeah" + +t = { + y: do + number = 100 + (x) -> x + number +} + +(y=(do + x = 10 + 2 + x), k=do + "nothing") -> do + "uhhh" + diff --git a/tests/outputs/do.lua b/tests/outputs/do.lua new file mode 100644 index 00000000..bfd7090b --- /dev/null +++ b/tests/outputs/do.lua @@ -0,0 +1,48 @@ +do + print("hello") + print("world") +end +local x +do + print("hello") + x = print("world") +end +local y +do + local things = "shhh" + y = function() + return "hello: " .. things + end +end +local _ +_ = function() + if something then + do + return "yeah" + end + end +end +local t = { + y = (function() + local number = 100 + return function(x) + return x + number + end + end)() +} +return function(y, k) + if y == nil then + y = ((function() + x = 10 + 2 + return x + end)()) + end + if k == nil then + do + k = "nothing" + end + end + do + return "uhhh" + end +end \ No newline at end of file From 13130134334adcbde0b469e385d7657f080d02f3 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 1 Nov 2012 07:27:52 -0700 Subject: [PATCH 022/554] with can take an assignment statement #46 --- moonscript/parse.lua | 7 ++++--- moonscript/transform.lua | 17 +++++++++++++++- moonscript/transform.moon | 15 ++++++++++++-- tests/inputs/with.moon | 26 +++++++++++++++++++++++++ tests/outputs/with.lua | 41 ++++++++++++++++++++++++++++++++++++++- 5 files changed, 99 insertions(+), 7 deletions(-) diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 7f86ab7c..db9a32c5 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -205,7 +205,7 @@ end -- the if statement only takes a single lhs, so we wrap in table to git to -- "assign" tuple format -local function format_assign_for_if(lhs, assign) +local function format_single_assign(lhs, assign) if assign then return format_assign({lhs}, assign) end @@ -413,7 +413,8 @@ local build_grammar = wrap_env(function() Return = key"return" * (ExpListLow/mark"explist" + C"") / mark"return", - With = key"with" * DisableDo * ensure(Exp, PopDo) * key"do"^-1 * Body / mark"with", + WithExp = Ct(ExpList) * Assign^-1 / format_assign, + With = key"with" * DisableDo * ensure(WithExp, PopDo) * key"do"^-1 * Body / mark"with", Switch = key"switch" * DisableDo * ensure(Exp, PopDo) * key"do"^-1 * Space^-1 * Break * SwitchBlock / mark"switch", @@ -421,7 +422,7 @@ local build_grammar = wrap_env(function() SwitchCase = key"when" * Exp * key"then"^-1 * Body / mark"case", SwitchElse = key"else" * Body / mark"else", - IfCond = Exp * Assign^-1 / format_assign_for_if, + IfCond = Exp * Assign^-1 / format_single_assign, If = key"if" * IfCond * key"then"^-1 * Body * ((Break * CheckIndent)^-1 * EmptyLine^0 * key"elseif" * pos(IfCond) * key"then"^-1 * Body / mark"elseif")^0 * diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 4cab6399..30665812 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -746,11 +746,26 @@ Statement = Transformer({ with = function(self, node, ret) local _, exp, block = unpack(node) local scope_name = NameProxy("with") + local named_assign + if ntype(exp) == "assign" then + local names, values = unpack(exp, 2) + local assign_name = names[1] + exp = values[1] + values[1] = scope_name + named_assign = { + "assign", + names, + values + } + end return build["do"]({ - build.assign_one(scope_name, exp), Run(function(self) return self:set("scope_var", scope_name) end), + build.assign_one(scope_name, exp), + build.group({ + named_assign + }), build.group(block), (function() if ret then diff --git a/moonscript/transform.moon b/moonscript/transform.moon index 374f4e28..791143fa 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -347,11 +347,22 @@ Statement = Transformer { with: (node, ret) => _, exp, block = unpack node + scope_name = NameProxy "with" - build["do"] { - build.assign_one scope_name, exp + + named_assign = if ntype(exp) == "assign" + names, values = unpack exp, 2 + assign_name = names[1] + exp = values[1] + values[1] = scope_name + {"assign", names, values} + + build.do { Run => @set "scope_var", scope_name + build.assign_one scope_name, exp + build.group { named_assign } build.group block + if ret ret scope_name } diff --git a/tests/inputs/with.moon b/tests/inputs/with.moon index e9b35acd..2f0bcaf1 100644 --- a/tests/inputs/with.moon +++ b/tests/inputs/with.moon @@ -36,3 +36,29 @@ with foo .prop\send(one) .prop\send one + +-- + +with a, b -- b is lost + print .world + +mod = with _M = {} + .Thing = "hi" + +-- operate on a only +with a, b = something, pooh + print .world + +x = with a, b = 1, 2 + print a + b + +print with a, b = 1, 2 + print a + b + +-- assignment lhs must be evaluated in the order they appear +p = with hello!.x, world!.y = 1, 2 + print a + b + + + + diff --git a/tests/outputs/with.lua b/tests/outputs/with.lua index 7d9ee768..469e434e 100644 --- a/tests/outputs/with.lua +++ b/tests/outputs/with.lua @@ -45,5 +45,44 @@ do local _ = _with_0:prop("something").hello _with_0.prop:send(one) _with_0.prop:send(one) - return _with_0 +end +do + local _with_0 = a, b + print(_with_0.world) +end +local mod +do + local _with_0 = { } + local _M = _with_0 + _with_0.Thing = "hi" + mod = _with_0 +end +do + local _with_0 = something + local b + a, b = _with_0, pooh + print(_with_0.world) +end +do + local _with_0 = 1 + local b + a, b = _with_0, 2 + print(a + b) + x = _with_0 +end +print((function() + do + local _with_0 = 1 + local b + a, b = _with_0, 2 + print(a + b) + return _with_0 + end +end)()) +local p +do + local _with_0 = 1 + hello().x, world().y = _with_0, 2 + print(a + b) + p = _with_0 end \ No newline at end of file From 481e0f6c6681b3d0be062e57470c4399ab33b50e Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 1 Nov 2012 08:00:21 -0700 Subject: [PATCH 023/554] add or= an and= operators --- moonscript/parse.lua | 2 +- tests/inputs/syntax.moon | 5 +++++ tests/outputs/syntax.lua | 5 ++++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/moonscript/parse.lua b/moonscript/parse.lua index db9a32c5..f2ce2c0b 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -449,7 +449,7 @@ local build_grammar = wrap_env(function() CompClause = CompFor + key"when" * Exp / mark"when", Assign = sym"=" * (Ct(With + If + Switch) + Ct(TableBlock + ExpListLow)) / mark"assign", - Update = ((sym"..=" + sym"+=" + sym"-=" + sym"*=" + sym"/=" + sym"%=") / trim) * Exp / mark"update", + Update = ((sym"..=" + sym"+=" + sym"-=" + sym"*=" + sym"/=" + sym"%=" + sym"or=" + sym"and=") / trim) * Exp / mark"update", -- we can ignore precedence for now OtherOps = op"or" + op"and" + op"<=" + op">=" + op"~=" + op"!=" + op"==" + op".." + op"<" + op">", diff --git a/tests/inputs/syntax.moon b/tests/inputs/syntax.moon index e9712162..8aeb55af 100644 --- a/tests/inputs/syntax.moon +++ b/tests/inputs/syntax.moon @@ -232,4 +232,9 @@ a /= func "cool" x.then = "hello" x.while.true = "hello" +-- + +x or= "hello" +x and= "hello" + -- cooool diff --git a/tests/outputs/syntax.lua b/tests/outputs/syntax.lua index 1fd64485..4430990e 100644 --- a/tests/outputs/syntax.lua +++ b/tests/outputs/syntax.lua @@ -228,4 +228,7 @@ a = a * (3 + 5) a = a * 3 a = a / func("cool") x["then"] = "hello" -x["while"]["true"] = "hello" \ No newline at end of file +x["while"]["true"] = "hello" +x = x or "hello" +x = x and "hello" +return x \ No newline at end of file From bcb4327fd8c5f687ce78e3279e2934943280a1bd Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 1 Nov 2012 08:03:27 -0700 Subject: [PATCH 024/554] remove concept of non atomic value --- moonscript/compile/format.lua | 6 ------ moonscript/compile/format.moon | 8 +------- moonscript/compile/statement.lua | 26 ++++---------------------- moonscript/compile/statement.moon | 11 ++--------- moonscript/compile/value.lua | 5 ----- moonscript/compile/value.moon | 6 ------ tests/outputs/loops.lua | 2 +- tests/outputs/syntax.lua | 4 +--- 8 files changed, 9 insertions(+), 59 deletions(-) diff --git a/moonscript/compile/format.lua b/moonscript/compile/format.lua index db30ef78..ee41f6bc 100644 --- a/moonscript/compile/format.lua +++ b/moonscript/compile/format.lua @@ -32,9 +32,6 @@ moonlib = { }) end } -non_atomic = Set({ - "update" -}) has_value = function(node) if ntype(node) == "chain" then local ctype = ntype(node[#node]) @@ -43,9 +40,6 @@ has_value = function(node) return true end end -is_non_atomic = function(node) - return non_atomic[ntype(node)] -end count_lines = function(str) local count = 1 for _ in str:gmatch("\n") do diff --git a/moonscript/compile/format.moon b/moonscript/compile/format.moon index 218aa675..f692ec8d 100644 --- a/moonscript/compile/format.moon +++ b/moonscript/compile/format.moon @@ -7,7 +7,7 @@ import Set from require "moonscript.data" import ntype from require "moonscript.types" import concat, insert from table -export indent_char, default_return, moonlib, cascading, non_atomic, has_value, is_non_atomic +export indent_char, default_return, moonlib, cascading, has_value export count_lines, user_error indent_char = " " @@ -23,9 +23,6 @@ moonlib = bind: (tbl, name) -> concat {"moon.bind(", tbl, ".", name, ", ", tbl, ")"} --- an action that can't be completed in a single line -non_atomic = Set{ "update" } - -- does this always return a value has_value = (node) -> if ntype(node) == "chain" @@ -34,9 +31,6 @@ has_value = (node) -> else true -is_non_atomic = (node) -> - non_atomic[ntype(node)] - count_lines = (str) -> count = 1 count += 1 for _ in str\gmatch "\n" diff --git a/moonscript/compile/statement.lua b/moonscript/compile/statement.lua index 0a5039e2..8ade5a86 100644 --- a/moonscript/compile/statement.lua +++ b/moonscript/compile/statement.lua @@ -159,29 +159,11 @@ line_compile = { end, ["while"] = function(self, node) local _, cond, block = unpack(node) - local out - if is_non_atomic(cond) then - do - local _with_0 = self:block("while true do") - _with_0:stm({ - "if", - { - "not", - cond - }, - { - { - "break" - } - } - }) - out = _with_0 - end - else - out = self:block(self:line("while ", self:value(cond), " do")) + do + local _with_0 = self:block(self:line("while ", self:value(cond), " do")) + _with_0:stms(block) + return _with_0 end - out:stms(block) - return out end, ["for"] = function(self, node) local _, name, bounds, block = unpack(node) diff --git a/moonscript/compile/statement.moon b/moonscript/compile/statement.moon index 0f48f2aa..26d62a92 100644 --- a/moonscript/compile/statement.moon +++ b/moonscript/compile/statement.moon @@ -92,15 +92,8 @@ line_compile = while: (node) => _, cond, block = unpack node - - out = if is_non_atomic cond - with @block "while true do" - \stm {"if", {"not", cond}, {{"break"}}} - else - @block @line "while ", @value(cond), " do" - - out\stms block - out + with @block @line "while ", @value(cond), " do" + \stms block for: (node) => _, name, bounds, block = unpack node diff --git a/moonscript/compile/value.lua b/moonscript/compile/value.lua index 77cb60cb..6ad30f9a 100644 --- a/moonscript/compile/value.lua +++ b/moonscript/compile/value.lua @@ -34,11 +34,6 @@ value_compile = { return _with_0 end end, - update = function(self, node) - local _, name = unpack(node) - self:stm(node) - return self:name(name) - end, explist = function(self, node) do local _with_0 = self:line() diff --git a/moonscript/compile/value.moon b/moonscript/compile/value.moon index 8c578124..aa86999d 100644 --- a/moonscript/compile/value.moon +++ b/moonscript/compile/value.moon @@ -24,12 +24,6 @@ value_compile = with @line! \append_list [_comp i,v for i,v in ipairs node when i > 1], " " - -- TODO refactor - update: (node) => - _, name = unpack node - @stm node - @name name - -- list of expressions separated by commas explist: (node) => with @line! diff --git a/tests/outputs/loops.lua b/tests/outputs/loops.lua index eff6447e..f538eafd 100644 --- a/tests/outputs/loops.lua +++ b/tests/outputs/loops.lua @@ -134,8 +134,8 @@ x = (function() local _accum_0 = { } local _len_0 = 0 while i < 10 do + local _value_0 i = i + 1 - local _value_0 = i if _value_0 ~= nil then _len_0 = _len_0 + 1 _accum_0[_len_0] = _value_0 diff --git a/tests/outputs/syntax.lua b/tests/outputs/syntax.lua index 4430990e..cb6abb69 100644 --- a/tests/outputs/syntax.lua +++ b/tests/outputs/syntax.lua @@ -156,7 +156,6 @@ for _index_0 = 1, #_list_0 do _ = ((function() if ntype(v) == "fndef" then x = x + 1 - return x end end)()) end @@ -230,5 +229,4 @@ a = a / func("cool") x["then"] = "hello" x["while"]["true"] = "hello" x = x or "hello" -x = x and "hello" -return x \ No newline at end of file +x = x and "hello" \ No newline at end of file From 97394fbbc9ec4c909d587acbbbcca5251f1827b3 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 1 Nov 2012 08:56:54 -0700 Subject: [PATCH 025/554] classes can be expressions, classes don't require name or body anymore --- moonscript/parse.lua | 7 +- moonscript/transform.lua | 56 +++++++---- moonscript/transform.moon | 46 +++++---- moonscript/types.lua | 12 ++- moonscript/types.moon | 13 ++- tests/inputs/class.moon | 7 ++ tests/outputs/class.lua | 196 ++++++++++++++++++++++++++++++++++++++ 7 files changed, 288 insertions(+), 49 deletions(-) diff --git a/moonscript/parse.lua b/moonscript/parse.lua index f2ce2c0b..ea5f2a83 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -383,7 +383,7 @@ local build_grammar = wrap_env(function() Line = (CheckIndent * Statement + Space * #Stop), Statement = pos( - Import + While + With + For + ForEach + Switch + Return + ClassDecl + + Import + While + With + For + ForEach + Switch + Return + Local + Export + BreakLoop + Ct(ExpList) * (Update + Assign)^-1 / format_assign ) * Space * (( @@ -467,6 +467,7 @@ local build_grammar = wrap_env(function() If + Unless + Switch + With + + ClassDecl + ForEach + For + While + Cmt(Do, check_do) + sym"-" * -SomeSpace * Exp / mark"minus" + @@ -552,10 +553,10 @@ local build_grammar = wrap_env(function() TableBlockInner = Ct(KeyValueLine * (SpaceBreak^1 * KeyValueLine)^0), TableBlock = SpaceBreak^1 * Advance * ensure(TableBlockInner, PopIndent) / mark"table", - ClassDecl = key"class" * Assignable * (key"extends" * PreventIndent * ensure(Exp, PopIndent) + C"")^-1 * ClassBlock / mark"class", + ClassDecl = key"class" * (Assignable + Cc(nil)) * (key"extends" * PreventIndent * ensure(Exp, PopIndent) + C"")^-1 * (ClassBlock + Ct("")) / mark"class", ClassBlock = SpaceBreak^1 * Advance * - Ct(ClassLine * (SpaceBreak^1 * ClassLine)^0) * PopIndent, + Ct(ClassLine * (SpaceBreak^1 * ClassLine)^0) * PopIndent, ClassLine = CheckIndent * (( KeyValueList / mark"props" + Statement / mark"stm" + diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 30665812..2d00faba 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -975,20 +975,23 @@ Statement = Transformer({ constructor.arrow = "fat" end local real_name - if ntype(name) == "chain" then + local _exp_0 = ntype(name) + if "chain" == _exp_0 then local last = name[#name] - local _exp_0 = ntype(last) - if "dot" == _exp_0 then + local _exp_1 = ntype(last) + if "dot" == _exp_1 then real_name = { "string", '"', last[2] } - elseif "index" == _exp_0 then + elseif "index" == _exp_1 then real_name = last[2] else real_name = "nil" end + elseif "nil" == _exp_0 then + real_name = "nil" else real_name = { "string", @@ -1112,7 +1115,9 @@ Statement = Transformer({ local _with_0 = build local out_body = { Run(function(self) - self:put_name(name) + if name then + self:put_name(name) + end return self:set("super", function(block, chain) if chain then local slice = (function() @@ -1134,8 +1139,8 @@ Statement = Transformer({ if head == nil then return parent_cls_name end - local _exp_0 = head[1] - if "call" == _exp_0 then + local _exp_1 = head[1] + if "call" == _exp_1 then local calling_name = block:get("current_block") slice[1] = { "call", @@ -1155,7 +1160,7 @@ Statement = Transformer({ calling_name }) end - elseif "colon" == _exp_0 then + elseif "colon" == _exp_1 then local call = head[3] insert(new_chain, { "dot", @@ -1186,7 +1191,7 @@ Statement = Transformer({ properties }), _with_0.assign_one(base_name:chain("__index"), base_name), - build["if"]({ + _with_0["if"]({ cond = parent_cls_name, ["then"] = { _with_0.chain({ @@ -1215,11 +1220,9 @@ Statement = Transformer({ _with_0.assign_one(LocalName("self"), cls_name), _with_0.group(statements) } - else - return { } end end)()), - build["if"]({ + _with_0["if"]({ cond = { "exp", parent_cls_name, @@ -1236,7 +1239,13 @@ Statement = Transformer({ }) } }), - _with_0.assign_one(name, cls_name), + _with_0.group((function() + if name then + return { + _with_0.assign_one(name, cls_name) + } + end + end)()), (function() if ret then return ret(cls_name) @@ -1245,15 +1254,17 @@ Statement = Transformer({ } hoist_declarations(out_body) value = _with_0.group({ - (function() + _with_0.group((function() if ntype(name) == "value" then - return _with_0.declare({ - names = { - name - } - }) + return { + _with_0.declare({ + names = { + name + } + }) + } end - end)(), + end)()), _with_0["do"](out_body) }) end @@ -1415,6 +1426,11 @@ Value = Transformer({ decorated = function(self, node) return self.transform.statement(node) end, + class = function(self, node) + return build.block_exp({ + node + }) + end, string = function(self, node) local delim = node[2] local convert_part diff --git a/moonscript/transform.moon b/moonscript/transform.moon index 791143fa..d34dae7d 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -505,17 +505,20 @@ Statement = Transformer { smart_node constructor constructor.arrow = "fat" - real_name = if ntype(name) == "chain" - last = name[#name] - switch ntype last - when "dot" - {"string", '"', last[2]} - when "index" - last[2] - else - "nil" - else - {"string", '"', name} + real_name = switch ntype(name) + when "chain" + last = name[#name] + switch ntype last + when "dot" + {"string", '"', last[2]} + when "index" + last[2] + else + "nil" + when "nil" + "nil" + else + {"string", '"', name} cls = build.table { {"__init", constructor} @@ -569,7 +572,7 @@ Statement = Transformer { out_body = { Run => -- make sure we don't assign the class to a local inside the do - @put_name name + @put_name name if name @set "super", (block, chain) -> if chain @@ -608,7 +611,7 @@ Statement = Transformer { .assign_one base_name, {"table", properties} .assign_one base_name\chain"__index", base_name - build["if"] { + .if { cond: parent_cls_name then: { .chain { @@ -624,13 +627,13 @@ Statement = Transformer { .assign_one cls_name, cls .assign_one base_name\chain"__class", cls_name - .group if #statements > 0 { + .group if #statements > 0 then { .assign_one LocalName"self", cls_name .group statements - } else {} + } -- run the inherited callback - build["if"] { + .if { cond: {"exp", parent_cls_name, "and", parent_cls_name\chain "__inherited" } @@ -641,7 +644,10 @@ Statement = Transformer { } } - .assign_one name, cls_name + .group if name then { + .assign_one name, cls_name + } + if ret ret cls_name } @@ -649,8 +655,9 @@ Statement = Transformer { hoist_declarations out_body value = .group { - if ntype(name) == "value" + .group if ntype(name) == "value" then { .declare names: {name} + } .do out_body } @@ -755,6 +762,9 @@ Value = Transformer { decorated: (node) => @transform.statement node + class: (node) => + build.block_exp { node } + string: (node) => delim = node[2] diff --git a/moonscript/types.lua b/moonscript/types.lua index 4ec240e3..d04b53b5 100644 --- a/moonscript/types.lua +++ b/moonscript/types.lua @@ -24,10 +24,13 @@ comprehension_has_value = function(comp) return is_value(comp[2]) end ntype = function(node) - if type(node) ~= "table" then - return "value" - else + local _exp_0 = type(node) + if "nil" == _exp_0 then + return "nil" + elseif "table" == _exp_0 then return node[1] + else + return "value" end end value_is_singular = function(node) @@ -175,6 +178,9 @@ end build = nil build = setmetatable({ group = function(body) + if body == nil then + body = { } + end return { "group", body diff --git a/moonscript/types.moon b/moonscript/types.moon index 11a83dcd..04a9e1e9 100644 --- a/moonscript/types.moon +++ b/moonscript/types.moon @@ -25,10 +25,13 @@ comprehension_has_value = (comp) -> -- type of node as string ntype = (node) -> - if type(node) != "table" - "value" - else - node[1] + switch type node + when "nil" + "nil" + when "table" + node[1] + else + "value" value_is_singular = (node) -> type(node) != "table" or node[1] != "exp" or #node == 2 @@ -102,7 +105,7 @@ make_builder = (name) -> build = nil build = setmetatable { - group: (body) -> + group: (body={}) -> {"group", body} do: (body) -> {"do", body} diff --git a/tests/inputs/class.moon b/tests/inputs/class.moon index 40c0957c..0deb37e8 100644 --- a/tests/inputs/class.moon +++ b/tests/inputs/class.moon @@ -146,7 +146,14 @@ class a.b["hello"] class (-> require "moon")!.Something extends Hello.World nil +-- + +a = class +b = class Something +c = class Something extends Hello +d = class extends World +print (class WhatsUp).__name -- diff --git a/tests/outputs/class.lua b/tests/outputs/class.lua index 4498f286..407f85d1 100644 --- a/tests/outputs/class.lua +++ b/tests/outputs/class.lua @@ -753,6 +753,202 @@ do return require("moon") end)().Something = _class_0 end +local a +do + local _parent_0 = nil + local _base_0 = { } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, ...) + if _parent_0 then + return _parent_0.__init(self, ...) + end + end, + __base = _base_0, + __name = nil, + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + a = _class_0 +end +local b +local Something +do + local _parent_0 = nil + local _base_0 = { } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, ...) + if _parent_0 then + return _parent_0.__init(self, ...) + end + end, + __base = _base_0, + __name = "Something", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Something = _class_0 + b = _class_0 +end +local c +do + local _parent_0 = Hello + local _base_0 = { } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, ...) + if _parent_0 then + return _parent_0.__init(self, ...) + end + end, + __base = _base_0, + __name = "Something", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Something = _class_0 + c = _class_0 +end +local d +do + local _parent_0 = World + local _base_0 = { } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, ...) + if _parent_0 then + return _parent_0.__init(self, ...) + end + end, + __base = _base_0, + __name = nil, + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + d = _class_0 +end +print(((function() + local WhatsUp + do + local _parent_0 = nil + local _base_0 = { } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, ...) + if _parent_0 then + return _parent_0.__init(self, ...) + end + end, + __base = _base_0, + __name = "WhatsUp", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + WhatsUp = _class_0 + return _class_0 + end +end)()).__name) do local _parent_0 = nil local _base_0 = { } From f98f82289117533e03d9edeb0ec88fbceb81191e Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 1 Nov 2012 09:19:04 -0700 Subject: [PATCH 026/554] extract class name from assign statement if anonymous class is being assigned --- moonscript/transform.lua | 38 ++++++++++++++++++++------------------ moonscript/transform.moon | 21 ++++++++++++--------- tests/outputs/class.lua | 4 ++-- 3 files changed, 34 insertions(+), 29 deletions(-) diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 2d00faba..a28b1333 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -463,24 +463,26 @@ Statement = Transformer({ t = ntype(value) end if types.cascading[t] then + local ret + ret = function(stm) + if types.is_value(stm) then + return { + "assign", + names, + { + stm + } + } + else + return stm + end + end transformed = build.group({ { "declare", names }, - self.transform.statement(value, function(stm) - if types.is_value(stm) then - return { - "assign", - names, - { - stm - } - } - else - return stm - end - end) + self.transform.statement(value, ret, node) }) end end @@ -897,7 +899,7 @@ Statement = Transformer({ if_stm }) end, - class = function(self, node, ret) + class = function(self, node, ret, parent_assign) local _, name, parent_val, body = unpack(node) local statements = { } local properties = { } @@ -974,10 +976,10 @@ Statement = Transformer({ smart_node(constructor) constructor.arrow = "fat" end - local real_name - local _exp_0 = ntype(name) + local real_name = name or parent_assign and parent_assign[2][1] + local _exp_0 = ntype(real_name) if "chain" == _exp_0 then - local last = name[#name] + local last = real_name[#real_name] local _exp_1 = ntype(last) if "dot" == _exp_1 then real_name = { @@ -996,7 +998,7 @@ Statement = Transformer({ real_name = { "string", '"', - name + real_name } end local cls = build.table({ diff --git a/moonscript/transform.moon b/moonscript/transform.moon index d34dae7d..38291624 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -209,13 +209,15 @@ Statement = Transformer { t = ntype value if types.cascading[t] + ret = (stm) -> + if types.is_value stm + {"assign", names, {stm}} + else + stm + build.group { {"declare", names} - @transform.statement value, (stm) -> - if types.is_value stm - {"assign", names, {stm}} - else - stm + @transform.statement value, ret, node } transformed or node @@ -456,7 +458,7 @@ Statement = Transformer { if_stm } - class: (node, ret) => + class: (node, ret, parent_assign) => _, name, parent_val, body = unpack node -- split apart properties and statements @@ -505,9 +507,10 @@ Statement = Transformer { smart_node constructor constructor.arrow = "fat" - real_name = switch ntype(name) + real_name = name or parent_assign and parent_assign[2][1] + real_name = switch ntype real_name when "chain" - last = name[#name] + last = real_name[#real_name] switch ntype last when "dot" {"string", '"', last[2]} @@ -518,7 +521,7 @@ Statement = Transformer { when "nil" "nil" else - {"string", '"', name} + {"string", '"', real_name} cls = build.table { {"__init", constructor} diff --git a/tests/outputs/class.lua b/tests/outputs/class.lua index 407f85d1..2156f398 100644 --- a/tests/outputs/class.lua +++ b/tests/outputs/class.lua @@ -768,7 +768,7 @@ do end end, __base = _base_0, - __name = nil, + __name = "a", __parent = _parent_0 }, { __index = function(cls, name) @@ -885,7 +885,7 @@ do end end, __base = _base_0, - __name = nil, + __name = "d", __parent = _parent_0 }, { __index = function(cls, name) From 77527601607ea98655dd0662bf352aa7ed1140b4 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 2 Nov 2012 09:12:05 -0700 Subject: [PATCH 027/554] @@variables should be assignable --- moonscript/parse.lua | 7 +++---- tests/inputs/syntax.moon | 3 +++ tests/outputs/syntax.lua | 2 ++ 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/moonscript/parse.lua b/moonscript/parse.lua index ea5f2a83..3db6f5fe 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -165,12 +165,12 @@ local function flatten_or_mark(name) end -- makes sure the last item in a chain is an index -local _assignable = { index = true, dot = true, slice = true } +local _chain_assignable = { index = true, dot = true, slice = true } local function is_assignable(node) local t = ntype(node) - return t == "self" or t == "value" or - t == "chain" and _assignable[ntype(node[#node])] + return t == "self" or t == "value" or t == "self_class" or + t == "chain" and _chain_assignable[ntype(node[#node])] end local function check_assignable(str, pos, value) @@ -188,7 +188,6 @@ local function format_assign(lhs_exps, assign) for _, assign_exp in ipairs(lhs_exps) do if not is_assignable(assign_exp) then - print(util.dump(assign_exp)) error {assign_exp, "left hand expression is not assignable"} end end diff --git a/tests/inputs/syntax.moon b/tests/inputs/syntax.moon index 8aeb55af..6cd1b02f 100644 --- a/tests/inputs/syntax.moon +++ b/tests/inputs/syntax.moon @@ -142,6 +142,9 @@ y /= 100 m %= 2 hello ..= "world" +@@something += 10 +@something += 10 + x = 0 (if ntype(v) == "fndef" then x += 1) for v in *values diff --git a/tests/outputs/syntax.lua b/tests/outputs/syntax.lua index cb6abb69..75b51431 100644 --- a/tests/outputs/syntax.lua +++ b/tests/outputs/syntax.lua @@ -149,6 +149,8 @@ y = y * 2 y = y / 100 local m = m % 2 local hello = hello .. "world" +self.__class.something = self.__class.something + 10 +self.something = self.something + 10 x = 0 local _list_0 = values for _index_0 = 1, #_list_0 do From 07a01d94cd807489f44350cdf0231db56b1319f3 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 3 Nov 2012 18:19:31 -0700 Subject: [PATCH 028/554] update docs --- docs/reference.md | 340 ++++++++++++++++++++++++++++++++++--------- docs/standard_lib.md | 2 +- 2 files changed, 275 insertions(+), 67 deletions(-) diff --git a/docs/reference.md b/docs/reference.md index 9aba3071..d121e87e 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -1,6 +1,6 @@ target: reference/index template: reference - title: MoonScript v0.2.1 - Language Guide + title: MoonScript v0.2.2 - Language Guide short_name: lang -- MoonScript is a programming language that compiles to @@ -20,20 +20,27 @@ homepage are located at . ## Assignment -Unlike Lua, there is no `local` keyword. All assignments to names that are not -already defined will be declared as local to the scope of that declaration. If -you wish to create a global variable it must be done using the `export` -keyword. +Assigning to an undeclared name will cause it to be declared as a new local +variable. The language is dynamically typed so you can assign any value to any +variable. You can assign multiple names and values at once just like Lua: ```moon hello = "world" a,b,c = 1, 2, 3 + hello = 123 -- uses the existing variable ``` +If you wish to create a global variable it must be done using the +[`export`](#export) keyword. + +The `local` keyword can be used to forward declare a variable, or shadow an +existing one. + ## Update Assignment -`+=`, `-=`, `/=`, `*=`, `%=`, `..=` operators have been added for updating a value by -a certain amount. They are aliases for their expanded equivalents. +`+=`, `-=`, `/=`, `*=`, `%=`, `..=`, `or=`, `and=` operators have been added +for updating and assigning at the same time. They are aliases for their +expanded equivalents. ```moon x = 0 @@ -41,9 +48,12 @@ a certain amount. They are aliases for their expanded equivalents. s = "hello " s ..= "world" + + b = false + b and= true or false ``` -## Comments +## Comments Like Lua, comments start with `--` and continue to the end of the line. Comments are not written to the output. @@ -70,7 +80,6 @@ denoted using the arrow: `->` my_function() -- call the empty function ``` - The body of the function can either be one statement placed directly after the arrow, or it can be a series of statements indented on the following lines: @@ -98,9 +107,9 @@ argument names in parentheses: sum = (x, y) -> print "sum", x + y ``` -Functions can be called by listing the values of the arguments after the name -of the variable where the function is stored. When chaining together function -calls, the arguments are applied to the closest function to the left. +Functions can be called by listing the arguments after the name of an expresion +that evaluates to a function. When chaining together function calls, the +arguments are applied to the closest function to the left. ```moon sum 10, 20 @@ -117,6 +126,8 @@ right arguments get sent to the right functions. print "x:", sum(10, 20), "y:", sum(30, 40) ``` +There must not be any space between the opening parenthesis and the function. + Functions will coerce the last statement in their body into a return statement, this is called implicit return: @@ -133,7 +144,7 @@ And if you need to explicitly return, you can use the `return` keyword: Just like in Lua, functions can return multiple values. The last statement must be a list of values separated by commas: - + ```moon mystery = (x, y) -> x + y, x - y a,b = mystery 10, 20 @@ -146,7 +157,7 @@ calling a method, a special syntax is provided for creating functions which automatically includes a `self` argument. ```moon - func = (num) => self.value + num + func = (num) => @value + num ``` ### Argument Defaults @@ -188,8 +199,9 @@ the `-`. Consider the examples below. ``` The precedence of the first argument of a function call can also be controlled -using whitespace if the argument is a literal string.In Lua, it is common to -leave off parentheses when calling a function with a single string literal. +using whitespace if the argument is a literal string. In Lua, it is common to +leave off parentheses when calling a function with a single string or table +literal. When there is no space between a variable and a string literal, the function call takes precedence over any following expressions. No other @@ -249,7 +261,7 @@ instead of being part of the table. ``` Although uncommon, notice how we can give a deeper indentation for function -arguments if we know we will be using a lower indentation futher on. +arguments if we know we will be using a lower indentation further on. ```moon y = { my_func 1,2,3, @@ -299,7 +311,7 @@ The curly braces can be left off if a single table of key value pairs is being assigned. ```moon - profile = + profile = height: "4 feet", shoe_size: 13, favorite_foods: {"ice cream", "donuts"} @@ -348,7 +360,7 @@ same as the variable names, then the `:` prefix operator can be used: If you want the key of a field in the table to to be result of an expression, then you can wrap it in `[` `]`, just like in Lua. You can also use a string literal directly as a key, leaving out the square brackets. This is useful if -your key has any special chacters. +your key has any special characters. ```moon t = { @@ -360,12 +372,12 @@ your key has any special chacters. ## Comprehensions -Compiling provide a convenient syntax for constructing a new table by iterating -over some existing object and applying an expression to its values. There are -two kinds of comprehensions: list comprehensions and table comprehensions. They -both produce Lua tables; _list comprehensions_ accumulate values into an -array-like table, and _table comprehensions_ let you set both the key and the -value on each iteration. +Comprehensions provide a convenient syntax for constructing a new table by +iterating over some existing object and applying an expression to its values. +There are two kinds of comprehensions: list comprehensions and table +comprehensions. They both produce Lua tables; _list comprehensions_ accumulate +values into an array-like table, and _table comprehensions_ let you set both +the key and the value on each iteration. ### List Comprehensions @@ -405,10 +417,10 @@ Using multiple `for` clauses is the same as using nested loops: ### Table Comprehensions -The syntax for table comprehensions is very similar, differing by using `{` and +The syntax for table comprehensions is very similar, only differing by using `{` and `}` and taking two values from each iteration. -This example copies the key-value table `thing`: +This example makes a copy of the table`thing`: ```moon thing = { @@ -456,7 +468,7 @@ a step size in a `for` loop. Here we can set the minimum and maximum bounds, taking all items with indexes between 1 and 5 inclusive: - + ```moon slice = [item for item in *items[1,5]] ``` @@ -477,6 +489,15 @@ size and leave the other bounds blank. This takes all odd indexed items: (1, 3, slice = [item for item in *items[,,2]] ``` +## String Interpolation + +You can mix expressions into string literals using `#{}` syntax. + + ```moon + print "I am #{math.random! * 100}% sure." + ``` +String interpolation is only available in double quoted strings. + ## For Loop There are two for loop forms, just like in Lua. A numeric one and a generic one: @@ -486,12 +507,12 @@ There are two for loop forms, just like in Lua. A numeric one and a generic one: print i for k = 1,15,2 -- an optional step provided - print k + print k for key, value in pairs object print key, value ``` - + The slicing and `*` operators can be used, just like with comprehensions: ```moon @@ -510,7 +531,7 @@ single line: 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. +table if the value of that expression is not `nil`. Doubling every even number: @@ -523,7 +544,7 @@ Doubling every even number: ``` Filtering out odd numbers: - + ```moon my_numbers = {1,2,3,4,5,6} odds = for x in *my_numbers @@ -531,7 +552,7 @@ Filtering out odd numbers: ``` 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 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. @@ -563,6 +584,27 @@ Like for loops, the while loop can also be used an expression. Additionally, for a function to return the accumulated value of a while loop, the statement must be explicitly returned. +## Continue + +A `continue` statement can be used to skip the current iteration in a loop. + + ```moon + i = 0 + while i < 10 + continue if i % 2 ==0 + print i + ``` +`continue` can also be used with loop expressions to prevent that iteration +from accumulating into the result. This examples filters the array table into +just even numbers: + + ```moon + my_numbers = {1,2,3,4,5,6} + odds = for x in *my_numbers + continue if x % 2 == 1 + x + ``` + ## Conditionals ```moon @@ -611,7 +653,7 @@ assigned variable is only in scope for the body of the conditional, meaning it is never available if the value is not truthy. ```moon - if user = database\find_user "moon" + if user = database.find_user "moon" print user.name ``` @@ -727,7 +769,7 @@ functions, but for other types of objects, undesired results may occur. Consider the example below, the `clothes` property is shared amongst all instances, so modifications to it in one instance will show up in another: - ```moon + ```moononly class Person clothes: {} give_item: (name) => @@ -746,7 +788,7 @@ instances, so modifications to it in one instance will show up in another: The proper way to avoid this problem is to create the mutable state of the object in the constructor: - ```moon + ```moononly class Person new: => @clothes = {} @@ -767,19 +809,23 @@ properties and methods from another class. Here we extend our Inventory class, and limit the amount of items it can carry. +In this example, we don't define a constructor on the subclass, so the parent +class' constructor is called when we make a new instance. If we did define a +constructor then we can use the [`super`](#super) method to call the parent +constructor. + Whenever a class inherits from another, it sends a message to the parent class -by calling the method `__inherited` on the parent class if it exists. The -function recieves two arguments, the class that is being inherited and the +by calling the method `__inherited` on the parent class if it exists. The +function receives two arguments, the class that is being inherited and the child class. - ```moon + ```moononly class Shelf @__inherited: (child) => print @__name, "was inherited by", child.__name -- will print: Shelf was inherited by Cupboard class Cupboard extends Shelf - nil ``` ### Super @@ -874,7 +920,7 @@ If the class extends from anything, the parent class object is stored in We can create variables directly in the class object instead of in the *base* by using `@` in the front of the property name in a class declaration. - ```moon + ```moononly class Things @some_func: => print "Hello from", @__name @@ -888,7 +934,7 @@ by using `@` in the front of the property name in a class declaration. In expressions, we can use `@@` to access a value that is stored in the `__class` of `self`. Thus, `@@hello` is shorthand for `self.__class.hello`. - ```moon + ```moononly class Counter @count: 0 @@ -924,6 +970,20 @@ described above: These expressions are executed after all the properties have been added to the *base*. +All variables declared in the body of the class are local to the classes +properties. This is convenient for placing private values or helper functions +that only the class methods can access: + + + ```moononly + class MoreThings + secret = 123 + log = (msg) -> print "LOG:", msg + + some_method: => + log "hello world: " .. secret + + ``` ### `@` and `@@` Values @@ -933,17 +993,54 @@ that name accessed in `self` and `self.__class`. If they are used all by themselves, they are aliases for `self` and `self.__class`. + ```moon assert @ == self assert @@ == self.__class + ``` For example, a quick way to create a new instance of the same class from an instance method using `@@`: + ```moon some_instance_method = (...) => @@ ... + ``` + + +### Class Expressions + +The `class` syntax can also be used as an expression which can be assigned to a +variable or explicitly returned. + + ```moononly + x = class Bucket + drops: 0 + add_drop: => @drops += 1 + ``` + +### Anonymous classes + +The name can be left out when declaring a class. The `__name` attribute will be +`nil`, unless the class expression is in an assignment. The name on the left +hand side of the assignment is used instead of `nil`. + + + ```moononly + BigBucket = class extends Bucket + add_drop: => @drops += 10 + + assert Bucket.__name == "BigBucket" + ``` + +You can even leave off the body, meaning you can write a blank anonymous class +like this: + + ```moononly + x = class + ``` ## Export Statement -Because, by default, all assignments to variables that are not lexically visible will +Because all assignments to variables that are not lexically visible will be declared as local, special syntax is required to declare a variable globally. The export keyword makes it so any following assignments to the specified names @@ -954,7 +1051,6 @@ will not be assigned locally. var_name, var_name3 = "hello", "world" ``` - This is especially useful when declaring what will be externally visible in a module: @@ -986,6 +1082,9 @@ variables directly: Additionally, a class declaration can be prefixed with the export keyword in order to export it. +Export will have no effect if there is already a local variable of the same +name in scope. + ### Export All & Export Proper The `export` statement can also take special symbols `*` and `^`. @@ -1067,6 +1166,51 @@ Or... me = create_person "Leaf", {dad, mother, sister} ``` +In this usage, `with` can be seen as a special form of the K combinator. + +The expression in the `with` statement can also be an assignment, if you want +to give a name to the expression. + + ```moon + with str = "Hello" + print "original:", str + print "upper:", \upper! + ``` + +## Do + +When used as a statement, `do` works just like it does in Lua. + + ```moon + do + var = "hello" + print var + print var -- nil here + ``` + +MoonScript's `do` can also be used an expression . Allowing you to combine +multiple lines into one. The result of the `do` expression is the last +statement in its body. + + + ```moon + counter = do + i = 0 + -> + i += 1 + i + + print counter! + print counter! + ``` + + ```moon + tbl = { + key: do + print "assigning key!" + 1234 + } + ``` ## Function Stubs @@ -1154,7 +1298,7 @@ accessed, they just cant be modified: i, k = 100, 50 my_func = (add using k,i) -> - tmp = tmp + add -- a new local tmp is created + tmp = tmp + add -- a new local tmp is created i += tmp k += tmp @@ -1162,6 +1306,33 @@ accessed, they just cant be modified: print i,k -- these have been updated ``` +## Misc. + +### Implicit Returns on Files + +By default, a file will also implicitly return like a function. This is useful +for writing modules, where you can put your module's table as the last +statement in the file so it is returned when loaded with `require`. + + +### Writing Modules + +Lua 5.2 has removed the `module` function for creating modules. It is +recommended to return a table instead when defining a module. + +The `with` statement along with implicit return on a file provides a convenient +way to do this: + + + ```moonret + -- my_library.moon + with _M = {} + .SOME_CONSTANT = 100 + + .some_function = -> print .SOME_CONSTANT + + ``` + # MoonScript API ## `moonscript` Module @@ -1192,30 +1363,67 @@ The `moonloader`, when finding a valid path to a `.moon` file, will parse and compile the file in memory. The code is then turned into a function using the built in `load` function, which is run as the module. +### Load Functions + + +MoonScript provides `moonscript.load`, `moonscript.loadfile`, +`mooonscript.loadstring`, which are analogous to Lua's `load`, `loadfile`, and +`loadstring`. + +The MoonScript functions work the same as their counterparts, except they deal +with MoonScript code instead of Lua Code. + + + ```moononly + require "moonscript" + fn = moonscript.loadstring 'print "hi!"' + fn! + ``` + +All of these functions can take an optional last argument, a table of options. +The only option right now is `implicitly_return_root`. Setting this to `false` +makes it so the file does not implicitly return its last statement. + + + ```moononly + require "moonscript" + + fn = moonscript.loadstring "10" + print fn! -- prints "10" + + fn = moonscript.loadstring "10", implicitly_return_root: false + print fn! -- prints nothing + ``` + ## Error Rewriting -Runtime errors are given special attention when using the `moonloader`. -Because we start off as MoonScript, but run code as Lua, errors that happen -during runtime report their line numbers as they are in the compiled file. This -can make debugging particularly difficult. +Runtime errors are given special attention when running code using the `moon` +binary. Because we start off as MoonScript, but run code as Lua, errors that +happen during runtime report their line numbers as they are in the compiled +file. This can make debugging particularly difficult. -Consider the following file with a bug: +Consider the following file with a bug (note the invalid `z` variable): ```moon - add_numbers = (x,y) -> x + z - print add_numbers 10,0 + add_numbers = (x,y) -> x + z -- 1 + print add_numbers 10,0 -- 2 ``` The following error is generated: - moon:err.moon:1: attempt to perform arithmetic on global 'z' (a nil value) + moon: scrap.moon:1(3): attempt to perform arithmetic on global 'z' (a nil value) stack traceback: - err.moon:1: in function 'add_numbers' - err.moon:2: in main chunk + scrap.moon:1(3): in function 'add_numbers' + scrap.moon:2(5): in main chunk -Instead of the error being reported on line number 3, where it appears in the -Lua file, it is reported on line 1, where the faulty line originated. The -entire stack trace is rewritten in addition to the error. + +Notice how next to the file name there are two numbers. The first number is the +rewritten line number. The number in the parentheses is the original Lua line +number. + +The error in this example is being reported on line 1 of the `moon` file, which +corresponds to line 3 of the generated Lua code. The entire stack trace is rewritten in +addition to the error message. ## Programmatically Compiling @@ -1228,7 +1436,7 @@ Lua code from MoonScript code. Here is a quick example of how you would compile a MoonScript string to a Lua String: - ```moon + ```moononly require "moonscript.parse" require "moonscript.compile" @@ -1252,7 +1460,7 @@ String: Two tools are installed with MoonScript, `moon` and `moonc`. -`moonc` is for compiling MoonScript code to Lua. +`moonc` is for compiling MoonScript code to Lua. `moon` is for running MoonsScript code directly. ## `moon` @@ -1294,26 +1502,26 @@ for all MoonScript files and compile them. `moonc` can write to standard out by passing the `-p` flag. -Combined with `linotify` on linux, the `-w` flag can be used to watch all files -that match the given search path for changes, and then compile them only when -required. +The `-w` flag can be used to enable watch mode. `moonc` will stay running, and +watch for changes to the input files. If any of them change then they will be +compiled automatically. A full list of flags can be seen by passing the `-h` or `--help` flag. # License (MIT) Copyright (C) 2011 by Leaf Corcoran - + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE diff --git a/docs/standard_lib.md b/docs/standard_lib.md index 6b3a1c16..3aeeee3d 100644 --- a/docs/standard_lib.md +++ b/docs/standard_lib.md @@ -1,6 +1,6 @@ target: reference/standard_lib template: reference - title: MoonScript v0.2.1 - Standard Library + title: MoonScript v0.2.2 - Standard Library short_name: stdlib -- From 51a75272a384f13dacad2f132ea8285dd7208aea Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 3 Nov 2012 18:31:50 -0700 Subject: [PATCH 029/554] bump version --- moonscript/version.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/moonscript/version.lua b/moonscript/version.lua index f643c52d..7347ffda 100644 --- a/moonscript/version.lua +++ b/moonscript/version.lua @@ -1,7 +1,7 @@ module("moonscript.version", package.seeall) -version = "0.2.1-dev" +version = "0.2.2" function print_version() print("MoonScript version "..version) end From f11eb0d250412f5aa830c7d0dadee572eeb577d6 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 4 Nov 2012 13:39:42 -0800 Subject: [PATCH 030/554] update docs for assignment in conditionals --- docs/reference.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/reference.md b/docs/reference.md index d121e87e..cc6b8712 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -646,6 +646,8 @@ Conditionals can also be used in return statements and assignments: print message -- prints: I am very tall ``` +### With Assignment + `if` and `elseif` blocks can take an assignment in place of a conditional expression. Upon evaluating the conditional, the assignment will take place and the value that was assigned to will be used as the conditional expression. The @@ -657,6 +659,15 @@ is never available if the value is not truthy. print user.name ``` + ```moon + if hello = os.getenv "hello" + print "You have hello", hello + elseif world = os.getenv "world" + print "you have world", world + else + print "nothing :(" + ``` + ## Line Decorators For convenience, the for loop and if statement can be applied to single From 48662adc3b84849550bc9da444b129efb0c65c46 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 10 Nov 2012 22:09:36 -0800 Subject: [PATCH 031/554] let `class` be the key in an unbound table --- moonscript/parse.lua | 2 +- tests/inputs/syntax.moon | 2 ++ tests/outputs/syntax.lua | 3 +++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 3db6f5fe..81b19297 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -552,7 +552,7 @@ local build_grammar = wrap_env(function() TableBlockInner = Ct(KeyValueLine * (SpaceBreak^1 * KeyValueLine)^0), TableBlock = SpaceBreak^1 * Advance * ensure(TableBlockInner, PopIndent) / mark"table", - ClassDecl = key"class" * (Assignable + Cc(nil)) * (key"extends" * PreventIndent * ensure(Exp, PopIndent) + C"")^-1 * (ClassBlock + Ct("")) / mark"class", + ClassDecl = key"class" * -P":" * (Assignable + Cc(nil)) * (key"extends" * PreventIndent * ensure(Exp, PopIndent) + C"")^-1 * (ClassBlock + Ct("")) / mark"class", ClassBlock = SpaceBreak^1 * Advance * Ct(ClassLine * (SpaceBreak^1 * ClassLine)^0) * PopIndent, diff --git a/tests/inputs/syntax.moon b/tests/inputs/syntax.moon index 6cd1b02f..262945c7 100644 --- a/tests/inputs/syntax.moon +++ b/tests/inputs/syntax.moon @@ -157,6 +157,8 @@ hello = good: 230203 +div class: "cool" + 5 + what wack what whack + 5 diff --git a/tests/outputs/syntax.lua b/tests/outputs/syntax.lua index 75b51431..c78b4635 100644 --- a/tests/outputs/syntax.lua +++ b/tests/outputs/syntax.lua @@ -168,6 +168,9 @@ hello = { ["function"] = "okay", good = 230203 } +div({ + class = "cool" +}) _ = 5 + what(wack) what(whack + 5) _ = 5 - what(wack) From 3adaed672ebce0566ab466f95115a97a93e09c34 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 27 Nov 2012 18:35:07 -0800 Subject: [PATCH 032/554] make mtype not error when passed smart node fix #52 fixes error when returning if/elseif assignment block --- moonscript/transform.lua | 15 +++++++++++++-- moonscript/transform.moon | 12 ++++++++++-- tests/inputs/cond.moon | 6 ++++++ tests/outputs/cond.lua | 16 ++++++++++++++++ 4 files changed, 45 insertions(+), 4 deletions(-) diff --git a/moonscript/transform.lua b/moonscript/transform.lua index a28b1333..e2511f6b 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -5,7 +5,18 @@ local data = require("moonscript.data") local reversed = util.reversed local ntype, build, smart_node, is_slice, value_is_singular = types.ntype, types.build, types.smart_node, types.is_slice, types.value_is_singular local insert = table.insert -local mtype = util.moon.type +local mtype +do + local moon_type = util.moon.type + mtype = function(val) + local t = type(val) + if "table" == t and rawget(val, "__class") then + return moon_type(val) + else + return t + end + end +end local implicitly_return do local _parent_0 = nil @@ -182,7 +193,7 @@ apply_to_last = function(stms, fn) local last_exp_id = 0 for i = #stms, 1, -1 do local stm = stms[i] - if stm and util.moon.type(stm) ~= Run then + if stm and mtype(stm) ~= Run then last_exp_id = i break end diff --git a/moonscript/transform.moon b/moonscript/transform.moon index 38291624..a83713a4 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -9,7 +9,15 @@ import reversed from util import ntype, build, smart_node, is_slice, value_is_singular from types import insert from table -mtype = util.moon.type +mtype = do + moon_type = util.moon.type + -- lets us check a smart node without throwing an error + (val) -> + t = type(val) + if "table" == t and rawget(val, "__class") + moon_type val + else + t export Statement, Value, NameProxy, LocalName, Run @@ -67,7 +75,7 @@ apply_to_last = (stms, fn) -> last_exp_id = 0 for i = #stms, 1, -1 stm = stms[i] - if stm and util.moon.type(stm) != Run + if stm and mtype(stm) != Run last_exp_id = i break diff --git a/tests/inputs/cond.moon b/tests/inputs/cond.moon index d4d26431..89097216 100644 --- a/tests/inputs/cond.moon +++ b/tests/inputs/cond.moon @@ -89,6 +89,12 @@ elseif z = true else four +kzy = -> + if something = true + 1 + elseif another = false + 2 + --- unless true diff --git a/tests/outputs/cond.lua b/tests/outputs/cond.lua index 5da6d042..036f5469 100644 --- a/tests/outputs/cond.lua +++ b/tests/outputs/cond.lua @@ -150,6 +150,22 @@ else end end end +local kzy +kzy = function() + do + local something = true + if something then + return 1 + else + do + local another = false + if another then + return 2 + end + end + end + end +end if not (true) then print("cool!") end From 89f4a83f2651da74704a21937477b879065705f7 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 27 Nov 2012 23:46:32 -0800 Subject: [PATCH 033/554] add destructuring assignment --- moonscript/compile.lua | 6 +- moonscript/compile.moon | 2 +- moonscript/parse.lua | 3 +- moonscript/transform.lua | 142 ++-------------- moonscript/transform.moon | 50 ++---- moonscript/transform/destructure.lua | 227 ++++++++++++++++++++++++++ moonscript/transform/destructure.moon | 109 +++++++++++++ moonscript/transform/names.lua | 140 ++++++++++++++++ moonscript/transform/names.moon | 43 +++++ tests/inputs/destructure.moon | 45 +++++ tests/outputs/destructure.lua | 88 ++++++++++ 11 files changed, 681 insertions(+), 174 deletions(-) create mode 100644 moonscript/transform/destructure.lua create mode 100644 moonscript/transform/destructure.moon create mode 100644 moonscript/transform/names.lua create mode 100644 moonscript/transform/names.moon create mode 100644 tests/inputs/destructure.moon create mode 100644 tests/outputs/destructure.lua diff --git a/moonscript/compile.lua b/moonscript/compile.lua index 0e200d8f..00dfc4e3 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -5,7 +5,11 @@ require("moonscript.compile.format") require("moonscript.compile.statement") require("moonscript.compile.value") local transform = require("moonscript.transform") -local NameProxy, LocalName = transform.NameProxy, transform.LocalName +local NameProxy, LocalName +do + local _table_0 = require("moonscript.transform.names") + NameProxy, LocalName = _table_0.NameProxy, _table_0.LocalName +end local Set do local _table_0 = require("moonscript.data") diff --git a/moonscript/compile.moon b/moonscript/compile.moon index 411ee9f4..e3c37409 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -9,7 +9,7 @@ require "moonscript.compile.value" transform = require "moonscript.transform" -import NameProxy, LocalName from transform +import NameProxy, LocalName from require "moonscript.transform.names" import Set from require "moonscript.data" import ntype from require "moonscript.types" diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 81b19297..b706104f 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -170,7 +170,8 @@ local _chain_assignable = { index = true, dot = true, slice = true } local function is_assignable(node) local t = ntype(node) return t == "self" or t == "value" or t == "self_class" or - t == "chain" and _chain_assignable[ntype(node[#node])] + t == "chain" and _chain_assignable[ntype(node[#node])] or + t == "table" end local function check_assignable(str, pos, value) diff --git a/moonscript/transform.lua b/moonscript/transform.lua index e2511f6b..1039ad99 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -5,6 +5,12 @@ local data = require("moonscript.data") local reversed = util.reversed local ntype, build, smart_node, is_slice, value_is_singular = types.ntype, types.build, types.smart_node, types.is_slice, types.value_is_singular local insert = table.insert +local NameProxy, LocalName +do + local _table_0 = require("moonscript.transform.names") + NameProxy, LocalName = _table_0.NameProxy, _table_0.LocalName +end +local destructure = require("moonscript.transform.destructure") local mtype do local moon_type = util.moon.type @@ -18,136 +24,6 @@ do end end local implicitly_return -do - local _parent_0 = nil - local _base_0 = { - get_name = function(self) - return self.name - end - } - _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end - local _class_0 = setmetatable({ - __init = function(self, name) - self.name = name - self[1] = "temp_name" - end, - __base = _base_0, - __name = "LocalName", - __parent = _parent_0 - }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, - __call = function(cls, ...) - local _self_0 = setmetatable({}, _base_0) - cls.__init(_self_0, ...) - return _self_0 - end - }) - _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end - LocalName = _class_0 -end -do - local _parent_0 = nil - local _base_0 = { - get_name = function(self, scope) - if not self.name then - self.name = scope:free_name(self.prefix, true) - end - return self.name - end, - chain = function(self, ...) - local items = { - ... - } - items = (function() - local _accum_0 = { } - local _len_0 = 0 - local _list_0 = items - for _index_0 = 1, #_list_0 do - local i = _list_0[_index_0] - local _value_0 - if type(i) == "string" then - _value_0 = { - "dot", - i - } - else - _value_0 = i - end - if _value_0 ~= nil then - _len_0 = _len_0 + 1 - _accum_0[_len_0] = _value_0 - end - end - return _accum_0 - end)() - return build.chain({ - base = self, - unpack(items) - }) - end, - index = function(self, key) - return build.chain({ - base = self, - { - "index", - key - } - }) - end, - __tostring = function(self) - if self.name then - return ("name<%s>"):format(self.name) - else - return ("name"):format(self.prefix) - end - end - } - _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end - local _class_0 = setmetatable({ - __init = function(self, prefix) - self.prefix = prefix - self[1] = "temp_name" - end, - __base = _base_0, - __name = "NameProxy", - __parent = _parent_0 - }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, - __call = function(cls, ...) - local _self_0 = setmetatable({}, _base_0) - cls.__init(_self_0, ...) - return _self_0 - end - }) - _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end - NameProxy = _class_0 -end do local _parent_0 = nil local _base_0 = { @@ -497,7 +373,11 @@ Statement = Transformer({ }) end end - return transformed or node + node = transformed or node + if destructure.has_destructure(names) then + return destructure.split_assign(node) + end + return node end, continue = function(self, node) local continue_name = self:send("continue") diff --git a/moonscript/transform.moon b/moonscript/transform.moon index a83713a4..c34035d8 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -8,6 +8,9 @@ data = require "moonscript.data" import reversed from util import ntype, build, smart_node, is_slice, value_is_singular from types import insert from table +import NameProxy, LocalName from require "moonscript.transform.names" + +destructure = require "moonscript.transform.destructure" mtype = do moon_type = util.moon.type @@ -19,48 +22,10 @@ mtype = do else t -export Statement, Value, NameProxy, LocalName, Run +export Statement, Value, Run local implicitly_return --- always declares as local -class LocalName - new: (@name) => self[1] = "temp_name" - get_name: => @name - -class NameProxy - new: (@prefix) => - self[1] = "temp_name" - - get_name: (scope) => - if not @name - @name = scope\free_name @prefix, true - @name - - chain: (...) => - items = {...} -- todo: fix ... propagation - items = for i in *items - if type(i) == "string" - {"dot", i} - else - i - - build.chain { - base: self - unpack items - } - - index: (key) => - build.chain { - base: self, {"index", key} - } - - __tostring: => - if @name - ("name<%s>")\format @name - else - ("name")\format @prefix - class Run new: (@fn) => self[1] = "run" @@ -228,7 +193,12 @@ Statement = Transformer { @transform.statement value, ret, node } - transformed or node + node = transformed or node + + if destructure.has_destructure names + return destructure.split_assign node + + node continue: (node) => continue_name = @send "continue" diff --git a/moonscript/transform/destructure.lua b/moonscript/transform/destructure.lua new file mode 100644 index 00000000..fc8ebf1f --- /dev/null +++ b/moonscript/transform/destructure.lua @@ -0,0 +1,227 @@ +local ntype, build +do + local _table_0 = require("moonscript.types") + ntype, build = _table_0.ntype, _table_0.build +end +local NameProxy +do + local _table_0 = require("moonscript.transform.names") + NameProxy = _table_0.NameProxy +end +local insert = table.insert +local user_error +do + local _table_0 = require("moonscript.compile") + user_error = _table_0.user_error +end +local join +join = function(...) + do + local _with_0 = { } + local out = _with_0 + local i = 1 + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local tbl = _list_0[_index_0] + local _list_1 = tbl + for _index_1 = 1, #_list_1 do + local v = _list_1[_index_1] + out[i] = v + i = i + 1 + end + end + return _with_0 + end +end +local has_destructure +has_destructure = function(names) + local _list_0 = names + for _index_0 = 1, #_list_0 do + local n = _list_0[_index_0] + if ntype(n) == "table" then + return true + end + end + return false +end +local build_assign +build_assign = function(extracted_names, receiver) + local obj = NameProxy("obj") + local names = { } + local values = { } + local _list_0 = extracted_names + for _index_0 = 1, #_list_0 do + local tuple = _list_0[_index_0] + insert(names, tuple[1]) + insert(values, obj:chain(unpack(tuple[2]))) + end + return build.group({ + { + "declare", + names + }, + build["do"]({ + build.assign_one(obj, receiver), + { + "assign", + names, + values + } + }) + }) +end +local extract_assign_names +extract_assign_names = function(name, accum, prefix) + if accum == nil then + accum = { } + end + if prefix == nil then + prefix = { } + end + local i = 1 + local _list_0 = name[2] + for _index_0 = 1, #_list_0 do + local tuple = _list_0[_index_0] + local value, suffix + if #tuple == 1 then + local s = { + "index", + { + "number", + i + } + } + i = i + 1 + value, suffix = tuple[1], s + else + local key = tuple[1] + local s + if ntype(key) == "key_literal" then + s = { + "dot", + key[2] + } + else + s = { + "index", + key + } + end + value, suffix = tuple[2], s + end + suffix = join(prefix, { + suffix + }) + local t = ntype(value) + if t == "value" or t == "chain" or t == "self" then + insert(accum, { + value, + suffix + }) + elseif t == "table" then + extract_assign_names(value, accum, suffix) + else + user_error("Can't destructure value of type: " .. tostring(ntype(value))) + end + end + return accum +end +local split_assign +split_assign = function(assign) + local names, values = unpack(assign, 2) + local g = { } + local total_names = #names + local total_values = #values + local start = 1 + for i, n in ipairs(names) do + if ntype(n) == "table" then + if i > start then + local stop = i - 1 + insert(g, { + "assign", + (function() + local _accum_0 = { } + local _len_0 = 0 + for i = start, stop do + local _value_0 = names[i] + if _value_0 ~= nil then + _len_0 = _len_0 + 1 + _accum_0[_len_0] = _value_0 + end + end + return _accum_0 + end)(), + (function() + local _accum_0 = { } + local _len_0 = 0 + for i = start, stop do + local _value_0 = values[i] + if _value_0 ~= nil then + _len_0 = _len_0 + 1 + _accum_0[_len_0] = _value_0 + end + end + return _accum_0 + end)() + }) + end + local extracted = extract_assign_names(n) + insert(g, build_assign(extracted, values[i])) + start = i + 1 + end + end + if total_names >= start or total_values >= start then + local name_slice + if total_names < start then + name_slice = { + "_" + } + else + name_slice = (function() + local _accum_0 = { } + local _len_0 = 0 + for i = start, total_names do + local _value_0 = names[i] + if _value_0 ~= nil then + _len_0 = _len_0 + 1 + _accum_0[_len_0] = _value_0 + end + end + return _accum_0 + end)() + end + local value_slice + if total_values < start then + value_slice = { + "nil" + } + else + value_slice = (function() + local _accum_0 = { } + local _len_0 = 0 + for i = start, total_values do + local _value_0 = values[i] + if _value_0 ~= nil then + _len_0 = _len_0 + 1 + _accum_0[_len_0] = _value_0 + end + end + return _accum_0 + end)() + end + insert(g, { + "assign", + name_slice, + value_slice + }) + end + return build.group(g) +end +return { + has_destructure = has_destructure, + split_assign = split_assign, + extract_assign_names = extract_assign_names, + build_assign = build_assign +} diff --git a/moonscript/transform/destructure.moon b/moonscript/transform/destructure.moon new file mode 100644 index 00000000..07b615a6 --- /dev/null +++ b/moonscript/transform/destructure.moon @@ -0,0 +1,109 @@ + +import ntype, build from require "moonscript.types" +import NameProxy from require "moonscript.transform.names" +import insert from table + +import user_error from require "moonscript.compile" + +join = (...) -> + with out = {} + i = 1 + for tbl in *{...} + for v in *tbl + out[i] = v + i += 1 + +has_destructure = (names) -> + for n in *names + return true if ntype(n) == "table" + false + +build_assign = (extracted_names, receiver) -> + obj = NameProxy "obj" + names = {} + values = {} + + for tuple in *extracted_names + insert names, tuple[1] + insert values, obj\chain unpack tuple[2] + + build.group { + {"declare", names} + build.do { + build.assign_one obj, receiver + {"assign", names, values} + } + } + +extract_assign_names = (name, accum={}, prefix={}) -> + i = 1 + for tuple in *name[2] + value, suffix = if #tuple == 1 + s = {"index", {"number", i}} + i += 1 + tuple[1], s + else + key = tuple[1] + s = if ntype(key) == "key_literal" + {"dot", key[2]} + else + {"index", key} + + tuple[2], s + + suffix = join prefix, {suffix} + + t = ntype value + if t == "value" or t == "chain" or t == "self" + insert accum, {value, suffix} + elseif t == "table" + extract_assign_names value, accum, suffix + else + user_error "Can't destructure value of type: #{ntype value}" + + accum + +-- applies to destructuring to a assign node +split_assign = (assign) -> + names, values = unpack assign, 2 + + g = {} + total_names = #names + total_values = #values + + -- We have to break apart the assign into groups of regular + -- assigns, and then the destructuring assignments + start = 1 + for i, n in ipairs names + if ntype(n) == "table" + if i > start + stop = i - 1 + insert g, { + "assign" + for i=start,stop + names[i] + for i=start,stop + values[i] + } + + extracted = extract_assign_names n + insert g, build_assign extracted, values[i] + + start = i + 1 + + if total_names >= start or total_values >= start + name_slice = if total_names < start + {"_"} + else + for i=start,total_names do names[i] + + value_slice = if total_values < start + {"nil"} + else + for i=start,total_values do values[i] + + insert g, {"assign", name_slice, value_slice} + + build.group g + +{ :has_destructure, :split_assign, :extract_assign_names, :build_assign } diff --git a/moonscript/transform/names.lua b/moonscript/transform/names.lua new file mode 100644 index 00000000..aa28dcdc --- /dev/null +++ b/moonscript/transform/names.lua @@ -0,0 +1,140 @@ +local build +do + local _table_0 = require("moonscript.types") + build = _table_0.build +end +local LocalName +do + local _parent_0 = nil + local _base_0 = { + get_name = function(self) + return self.name + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, name) + self.name = name + self[1] = "temp_name" + end, + __base = _base_0, + __name = "LocalName", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + LocalName = _class_0 +end +local NameProxy +do + local _parent_0 = nil + local _base_0 = { + get_name = function(self, scope) + if not self.name then + self.name = scope:free_name(self.prefix, true) + end + return self.name + end, + chain = function(self, ...) + local items = (function(...) + local _accum_0 = { } + local _len_0 = 0 + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local i = _list_0[_index_0] + local _value_0 + if type(i) == "string" then + _value_0 = { + "dot", + i + } + else + _value_0 = i + end + if _value_0 ~= nil then + _len_0 = _len_0 + 1 + _accum_0[_len_0] = _value_0 + end + end + return _accum_0 + end)(...) + return build.chain({ + base = self, + unpack(items) + }) + end, + index = function(self, key) + return build.chain({ + base = self, + { + "index", + key + } + }) + end, + __tostring = function(self) + if self.name then + return ("name<%s>"):format(self.name) + else + return ("name"):format(self.prefix) + end + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, prefix) + self.prefix = prefix + self[1] = "temp_name" + end, + __base = _base_0, + __name = "NameProxy", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + NameProxy = _class_0 +end +return { + NameProxy = NameProxy, + LocalName = LocalName +} diff --git a/moonscript/transform/names.moon b/moonscript/transform/names.moon new file mode 100644 index 00000000..f5059971 --- /dev/null +++ b/moonscript/transform/names.moon @@ -0,0 +1,43 @@ + +import build from require "moonscript.types" + +-- always declares as local +class LocalName + new: (@name) => self[1] = "temp_name" + get_name: => @name + +-- creates a unique name when used +class NameProxy + new: (@prefix) => + self[1] = "temp_name" + + get_name: (scope) => + if not @name + @name = scope\free_name @prefix, true + @name + + chain: (...) => + items = for i in *{...} + if type(i) == "string" + {"dot", i} + else + i + + build.chain { + base: self + unpack items + } + + index: (key) => + build.chain { + base: self, {"index", key} + } + + __tostring: => + if @name + ("name<%s>")\format @name + else + ("name")\format @prefix + + +{ :NameProxy, :LocalName } diff --git a/tests/inputs/destructure.moon b/tests/inputs/destructure.moon new file mode 100644 index 00000000..847ae730 --- /dev/null +++ b/tests/inputs/destructure.moon @@ -0,0 +1,45 @@ + +{a, b} = hello + +{{a}, b, {c}} = hello + +{ :hello, :world } = value + +{ yes: no, thing } = world + +{:a,:b,:c,:d} = yeah + +{a} = one, two +{b}, c = one +{d}, e = one, two + +x, {y} = one, two + +xx, yy = 1, 2 +{yy, xx} = {xx, yy} + +{a, :b, c, :d, e, :f, g} = tbl + +--- + +futurists = + sculptor: "Umberto Boccioni" + painter: "Vladimir Burliuk" + poet: + name: "F.T. Marinetti" + address: { + "Via Roma 42R" + "Bellagio, Italy 22021" + } + +{poet: {:name, address: {street, city}}} = futurists + +print name, street, city + +-- + +{ @world } = x +{ a.b, c.y, func!.z } = x + +{ world: @world } = x + diff --git a/tests/outputs/destructure.lua b/tests/outputs/destructure.lua new file mode 100644 index 00000000..9299b724 --- /dev/null +++ b/tests/outputs/destructure.lua @@ -0,0 +1,88 @@ +local a, b +do + local _obj_0 = hello + a, b = _obj_0[1], _obj_0[2] +end +local c +do + local _obj_0 = hello + a, b, c = _obj_0[1][1], _obj_0[2], _obj_0[3][1] +end +local hello, world +do + local _obj_0 = value + hello, world = _obj_0.hello, _obj_0.world +end +local no, thing +do + local _obj_0 = world + no, thing = _obj_0.yes, _obj_0[1] +end +local d +do + local _obj_0 = yeah + a, b, c, d = _obj_0.a, _obj_0.b, _obj_0.c, _obj_0.d +end +do + local _obj_0 = one + a = _obj_0[1] +end +local _ = two +do + local _obj_0 = one + b = _obj_0[1] +end +c = nil +do + local _obj_0 = one + d = _obj_0[1] +end +local e = two +local x = one +local y +do + local _obj_0 = two + y = _obj_0[1] +end +local xx, yy = 1, 2 +do + local _obj_0 = { + xx, + yy + } + yy, xx = _obj_0[1], _obj_0[2] +end +local f, g +do + local _obj_0 = tbl + a, b, c, d, e, f, g = _obj_0[1], _obj_0.b, _obj_0[2], _obj_0.d, _obj_0[3], _obj_0.f, _obj_0[4] +end +local futurists = { + sculptor = "Umberto Boccioni", + painter = "Vladimir Burliuk", + poet = { + name = "F.T. Marinetti", + address = { + "Via Roma 42R", + "Bellagio, Italy 22021" + } + } +} +local name, street, city +do + local _obj_0 = futurists + name, street, city = _obj_0.poet.name, _obj_0.poet.address[1], _obj_0.poet.address[2] +end +print(name, street, city) +do + local _obj_0 = x + self.world = _obj_0[1] +end +do + local _obj_0 = x + a.b, c.y, func().z = _obj_0[1], _obj_0[2], _obj_0[3] +end +do + local _obj_0 = x + self.world = _obj_0.world +end \ No newline at end of file From 3e42d06464c7d75bb94cb6635806b43ac5952f36 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 28 Nov 2012 00:04:41 -0800 Subject: [PATCH 034/554] get rid of the format module, refactor some code --- moonscript/compile.lua | 6 ++-- moonscript/compile.moon | 5 +-- moonscript/compile/format.lua | 49 --------------------------- moonscript/compile/format.moon | 38 --------------------- moonscript/compile/statement.lua | 1 - moonscript/compile/statement.moon | 1 - moonscript/compile/value.lua | 6 +++- moonscript/compile/value.moon | 4 +-- moonscript/errors.lua | 6 ++++ moonscript/errors.moon | 5 ++- moonscript/transform/destructure.lua | 2 +- moonscript/transform/destructure.moon | 2 +- moonscript/types.lua | 8 +++++ moonscript/types.moon | 10 +++++- 14 files changed, 42 insertions(+), 101 deletions(-) delete mode 100644 moonscript/compile/format.lua delete mode 100644 moonscript/compile/format.moon diff --git a/moonscript/compile.lua b/moonscript/compile.lua index 00dfc4e3..9bfc282d 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -1,7 +1,6 @@ module("moonscript.compile", package.seeall) local util = require("moonscript.util") local dump = require("moonscript.dump") -require("moonscript.compile.format") require("moonscript.compile.statement") require("moonscript.compile.value") local transform = require("moonscript.transform") @@ -15,14 +14,15 @@ do local _table_0 = require("moonscript.data") Set = _table_0.Set end -local ntype +local ntype, has_value do local _table_0 = require("moonscript.types") - ntype = _table_0.ntype + ntype, has_value = _table_0.ntype, _table_0.has_value end local concat, insert = table.concat, table.insert local pos_to_line, get_closest_line, trim = util.pos_to_line, util.get_closest_line, util.trim local mtype = util.moon.type +local indent_char = " " local Line, Lines do local _parent_0 = nil diff --git a/moonscript/compile.moon b/moonscript/compile.moon index e3c37409..53994866 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -3,7 +3,6 @@ module "moonscript.compile", package.seeall util = require "moonscript.util" dump = require "moonscript.dump" -require "moonscript.compile.format" require "moonscript.compile.statement" require "moonscript.compile.value" @@ -11,13 +10,15 @@ transform = require "moonscript.transform" import NameProxy, LocalName from require "moonscript.transform.names" import Set from require "moonscript.data" -import ntype from require "moonscript.types" +import ntype, has_value from require "moonscript.types" import concat, insert from table import pos_to_line, get_closest_line, trim from util mtype = util.moon.type +indent_char = " " + export tree, value, format_error export Block, RootBlock diff --git a/moonscript/compile/format.lua b/moonscript/compile/format.lua deleted file mode 100644 index ee41f6bc..00000000 --- a/moonscript/compile/format.lua +++ /dev/null @@ -1,49 +0,0 @@ -module("moonscript.compile", package.seeall) -local util = require("moonscript.util") -local data = require("moonscript.data") -local Set -do - local _table_0 = require("moonscript.data") - Set = _table_0.Set -end -local ntype -do - local _table_0 = require("moonscript.types") - ntype = _table_0.ntype -end -local concat, insert = table.concat, table.insert -indent_char = " " -user_error = function(...) - return error({ - "user-error", - ... - }) -end -moonlib = { - bind = function(tbl, name) - return concat({ - "moon.bind(", - tbl, - ".", - name, - ", ", - tbl, - ")" - }) - end -} -has_value = function(node) - if ntype(node) == "chain" then - local ctype = ntype(node[#node]) - return ctype ~= "call" and ctype ~= "colon" - else - return true - end -end -count_lines = function(str) - local count = 1 - for _ in str:gmatch("\n") do - count = count + 1 - end - return count -end diff --git a/moonscript/compile/format.moon b/moonscript/compile/format.moon deleted file mode 100644 index f692ec8d..00000000 --- a/moonscript/compile/format.moon +++ /dev/null @@ -1,38 +0,0 @@ -module "moonscript.compile", package.seeall - -util = require "moonscript.util" -data = require "moonscript.data" - -import Set from require "moonscript.data" -import ntype from require "moonscript.types" -import concat, insert from table - -export indent_char, default_return, moonlib, cascading, has_value -export count_lines, user_error - -indent_char = " " - -user_error = (...) -> - error {"user-error", ...} - --- manual_return = Set{"foreach", "for", "while"} --- cascading = Set{ "if", "with" } - --- TODO get RID OF THIAS -moonlib = - bind: (tbl, name) -> - concat {"moon.bind(", tbl, ".", name, ", ", tbl, ")"} - --- does this always return a value -has_value = (node) -> - if ntype(node) == "chain" - ctype = ntype(node[#node]) - ctype != "call" and ctype != "colon" - else - true - -count_lines = (str) -> - count = 1 - count += 1 for _ in str\gmatch "\n" - count - diff --git a/moonscript/compile/statement.lua b/moonscript/compile/statement.lua index 8ade5a86..fe7dd5b2 100644 --- a/moonscript/compile/statement.lua +++ b/moonscript/compile/statement.lua @@ -1,6 +1,5 @@ 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 reversed = util.reversed diff --git a/moonscript/compile/statement.moon b/moonscript/compile/statement.moon index 26d62a92..59d6021d 100644 --- a/moonscript/compile/statement.moon +++ b/moonscript/compile/statement.moon @@ -2,7 +2,6 @@ module "moonscript.compile", package.seeall util = require "moonscript.util" -require "moonscript.compile.format" dump = require "moonscript.dump" transform = require "moonscript.transform" diff --git a/moonscript/compile/value.lua b/moonscript/compile/value.lua index 6ad30f9a..a6d9d549 100644 --- a/moonscript/compile/value.lua +++ b/moonscript/compile/value.lua @@ -1,12 +1,16 @@ module("moonscript.compile", package.seeall) local util = require("moonscript.util") local data = require("moonscript.data") -require("moonscript.compile.format") local ntype do local _table_0 = require("moonscript.types") ntype = _table_0.ntype end +local user_error +do + local _table_0 = require("moonscript.errors") + user_error = _table_0.user_error +end local concat, insert = table.concat, table.insert local table_delim = "," value_compile = { diff --git a/moonscript/compile/value.moon b/moonscript/compile/value.moon index aa86999d..a066c2f0 100644 --- a/moonscript/compile/value.moon +++ b/moonscript/compile/value.moon @@ -4,9 +4,9 @@ module "moonscript.compile", package.seeall util = require "moonscript.util" data = require "moonscript.data" -require "moonscript.compile.format" - import ntype from require "moonscript.types" +import user_error from require "moonscript.errors" + import concat, insert from table export value_compile diff --git a/moonscript/errors.lua b/moonscript/errors.lua index d895e50c..fa4f681c 100644 --- a/moonscript/errors.lua +++ b/moonscript/errors.lua @@ -4,6 +4,12 @@ local util = require("moonscript.util") require("lpeg") local concat, insert = table.concat, table.insert local split, pos_to_line = util.split, util.pos_to_line +user_error = function(...) + return error({ + "user-error", + ... + }) +end local lookup_line lookup_line = function(fname, pos, cache) if not cache[fname] then diff --git a/moonscript/errors.moon b/moonscript/errors.moon index ede5fce1..6e480d1b 100644 --- a/moonscript/errors.moon +++ b/moonscript/errors.moon @@ -8,7 +8,10 @@ require "lpeg" import concat, insert from table import split, pos_to_line from util -export rewrite_traceback, truncate_traceback +export rewrite_traceback, truncate_traceback, user_error + +user_error = (...) -> + error {"user-error", ...} -- find the line number of `pos` chars into fname lookup_line = (fname, pos, cache) -> diff --git a/moonscript/transform/destructure.lua b/moonscript/transform/destructure.lua index fc8ebf1f..1c30c2cf 100644 --- a/moonscript/transform/destructure.lua +++ b/moonscript/transform/destructure.lua @@ -11,7 +11,7 @@ end local insert = table.insert local user_error do - local _table_0 = require("moonscript.compile") + local _table_0 = require("moonscript.errors") user_error = _table_0.user_error end local join diff --git a/moonscript/transform/destructure.moon b/moonscript/transform/destructure.moon index 07b615a6..96525696 100644 --- a/moonscript/transform/destructure.moon +++ b/moonscript/transform/destructure.moon @@ -3,7 +3,7 @@ import ntype, build from require "moonscript.types" import NameProxy from require "moonscript.transform.names" import insert from table -import user_error from require "moonscript.compile" +import user_error from require "moonscript.errors" join = (...) -> with out = {} diff --git a/moonscript/types.lua b/moonscript/types.lua index d04b53b5..d7b8897b 100644 --- a/moonscript/types.lua +++ b/moonscript/types.lua @@ -16,6 +16,14 @@ cascading = data.Set({ "class", "do" }) +has_value = function(node) + if ntype(node) == "chain" then + local ctype = ntype(node[#node]) + return ctype ~= "call" and ctype ~= "colon" + else + return true + end +end is_value = function(stm) local compile, transform = moonscript.compile, moonscript.transform return compile.Block:is_value(stm) or transform.Value:can_transform(stm) diff --git a/moonscript/types.moon b/moonscript/types.moon index 04a9e1e9..bdfd898c 100644 --- a/moonscript/types.moon +++ b/moonscript/types.moon @@ -4,7 +4,7 @@ data = require "moonscript.data" export ntype, smart_node, build, is_value export is_slice, manual_return, cascading, value_is_singular -export comprehension_has_value +export comprehension_has_value, has_value import insert from table @@ -16,6 +16,14 @@ manual_return = data.Set{"foreach", "for", "while", "return"} -- is the transformation to apply to the last statement in their body cascading = data.Set{ "if", "unless", "with", "switch", "class", "do" } +-- does this always return a value +has_value = (node) -> + if ntype(node) == "chain" + ctype = ntype(node[#node]) + ctype != "call" and ctype != "colon" + else + true + is_value = (stm) -> import compile, transform from moonscript compile.Block\is_value(stm) or transform.Value\can_transform stm From 33eb9510dd31cff4999f955aa5e1773f0254c2b0 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 28 Nov 2012 00:24:58 -0800 Subject: [PATCH 035/554] start refactoring out calls to module --- bin/moon | 6 +++--- bin/moonc | 2 +- moonscript/data.lua | 17 +++++++++------ moonscript/data.moon | 13 +++++------- moonscript/dump.lua | 7 ++++++- moonscript/dump.moon | 7 +++---- moonscript/errors.lua | 9 +++++++- moonscript/errors.moon | 6 +++--- moonscript/init.lua | 7 +++++-- moonscript/init.moon | 3 +-- moonscript/types.lua | 47 ++++++++++++++++++++++++++++-------------- moonscript/types.moon | 33 +++++++++++++++-------------- moonscript/util.lua | 43 ++++++++++++++++++++++++++------------ moonscript/util.moon | 30 ++++++++++++--------------- test2.moon | 8 +++---- 15 files changed, 141 insertions(+), 97 deletions(-) diff --git a/bin/moon b/bin/moon index 5665a809..ae455e98 100755 --- a/bin/moon +++ b/bin/moon @@ -1,10 +1,10 @@ #!/usr/bin/env lua require "alt_getopt" -require "moonscript.errors" require "moonscript" local util = require "moonscript.util" +local errors = require "moonscript.errors" -- moonloader and repl local opts, ind = alt_getopt.get_opts(arg, "cvhd", { version = "v", help = "h" }) @@ -77,8 +77,8 @@ if not opts.d then end) if err then - local truncated = moonscript.errors.truncate_traceback(util.trim(trace)) - local rewritten = moonscript.errors.rewrite_traceback(truncated, err) + local truncated = errors.truncate_traceback(util.trim(trace)) + local rewritten = errors.rewrite_traceback(truncated, err) if rewritten then print_err(rewritten) diff --git a/bin/moonc b/bin/moonc index 9410d2e4..5ed80aaa 100755 --- a/bin/moonc +++ b/bin/moonc @@ -4,7 +4,7 @@ module("moonscript", package.seeall) require "moonscript.parse" require "moonscript.compile" -require "moonscript.util" +local util = require "moonscript.util" require "alt_getopt" require "lfs" diff --git a/moonscript/data.lua b/moonscript/data.lua index ac9f3f0b..b968d91f 100644 --- a/moonscript/data.lua +++ b/moonscript/data.lua @@ -1,5 +1,5 @@ -module("moonscript.data", package.seeall) -local concat = table.concat +local concat, remove, insert = table.concat, table.remove, table.insert +local Set Set = function(items) local self = { } local _list_0 = items @@ -9,6 +9,7 @@ Set = function(items) end return self end +local Stack do local _parent_0 = nil local _base_0 = { @@ -16,10 +17,10 @@ do return "" end, pop = function(self) - return table.remove(self) + return remove(self) end, push = function(self, value) - table.insert(self, value) + insert(self, value) return value end, top = function(self) @@ -65,7 +66,7 @@ do end Stack = _class_0 end -lua_keywords = Set({ +local lua_keywords = Set({ 'and', 'break', 'do', @@ -88,4 +89,8 @@ lua_keywords = Set({ 'until', 'while' }) -return nil +return { + Set = Set, + Stack = Stack, + lua_keywords = lua_keywords +} diff --git a/moonscript/data.moon b/moonscript/data.moon index 8c18a84e..52df3d51 100644 --- a/moonscript/data.moon +++ b/moonscript/data.moon @@ -1,10 +1,6 @@ -- data structures & static data -module "moonscript.data", package.seeall -export Set, Stack -export lua_keywords - -import concat from table +import concat, remove, insert from table Set = (items) -> self = {} @@ -19,10 +15,10 @@ class Stack nil pop: => - table.remove self + remove self push: (value) => - table.insert self, value + insert self, value value top: => @@ -37,6 +33,7 @@ lua_keywords = Set{ 'until', 'while' } -nil + +{ :Set, :Stack, :lua_keywords } diff --git a/moonscript/dump.lua b/moonscript/dump.lua index 7b7fbc0c..5e46ed41 100644 --- a/moonscript/dump.lua +++ b/moonscript/dump.lua @@ -1,4 +1,3 @@ -module("moonscript.dump", package.seeall) local flat_value flat_value = function(op, depth) if depth == nil then @@ -24,9 +23,11 @@ flat_value = function(op, depth) local pos = op[-1] return "{" .. (pos and "[" .. pos .. "] " or "") .. table.concat(items, ", ") .. "}" end +local value value = function(op) return flat_value(op) end +local tree tree = function(block) local _list_0 = block for _index_0 = 1, #_list_0 do @@ -34,3 +35,7 @@ tree = function(block) print(flat_value(value)) end end +return { + value = value, + tree = tree +} diff --git a/moonscript/dump.moon b/moonscript/dump.moon index 077fc96b..a6373daa 100644 --- a/moonscript/dump.moon +++ b/moonscript/dump.moon @@ -1,8 +1,4 @@ -module "moonscript.dump", package.seeall - -export value, tree - flat_value = (op, depth=1) -> return '"'..op..'"' if type(op) == "string" return tostring(op) if type(op) != "table" @@ -17,3 +13,6 @@ value = (op) -> tree = (block) -> print flat_value value for value in *block + +{ :value, :tree } + diff --git a/moonscript/errors.lua b/moonscript/errors.lua index fa4f681c..3e5b9e25 100644 --- a/moonscript/errors.lua +++ b/moonscript/errors.lua @@ -1,9 +1,9 @@ -module("moonscript.errors", package.seeall) local moon = require("moonscript") local util = require("moonscript.util") require("lpeg") local concat, insert = table.concat, table.insert local split, pos_to_line = util.split, util.pos_to_line +local user_error user_error = function(...) return error({ "user-error", @@ -30,6 +30,7 @@ reverse_line_number = function(fname, line_table, line_num, cache) end return "unknown" end +local truncate_traceback truncate_traceback = function(traceback, chunk_func) if chunk_func == nil then chunk_func = "moonscript_chunk" @@ -58,6 +59,7 @@ truncate_traceback = function(traceback, chunk_func) traceback[#traceback] = traceback[#traceback]:gsub(rep, "main chunk") return concat(traceback, "\n") end +local rewrite_traceback rewrite_traceback = function(text, err) local line_tables = moon.line_tables local V, S, Ct, C = lpeg.V, lpeg.S, lpeg.Ct, lpeg.C @@ -103,3 +105,8 @@ rewrite_traceback = function(text, err) "\t" .. concat(match, "\n\t") }, "\n") end +return { + rewrite_traceback = rewrite_traceback, + truncate_traceback = truncate_traceback, + user_error = user_error +} diff --git a/moonscript/errors.moon b/moonscript/errors.moon index 6e480d1b..f077ccd5 100644 --- a/moonscript/errors.moon +++ b/moonscript/errors.moon @@ -1,5 +1,4 @@ -module "moonscript.errors", package.seeall moon = require "moonscript" util = require "moonscript.util" @@ -8,8 +7,6 @@ require "lpeg" import concat, insert from table import split, pos_to_line from util -export rewrite_traceback, truncate_traceback, user_error - user_error = (...) -> error {"user-error", ...} @@ -86,3 +83,6 @@ rewrite_traceback = (text, err) -> "\t" .. concat match, "\n\t" }, "\n" + +{ :rewrite_traceback, :truncate_traceback, :user_error } + diff --git a/moonscript/init.lua b/moonscript/init.lua index e8952243..61c65a41 100644 --- a/moonscript/init.lua +++ b/moonscript/init.lua @@ -1,9 +1,12 @@ module("moonscript", package.seeall) require("moonscript.compile") require("moonscript.parse") -require("moonscript.util") local concat, insert = table.concat, table.insert -local split, dump = util.split, util.dump +local split, dump +do + local _table_0 = require("moonscript.util") + split, dump = _table_0.split, _table_0.dump +end local lua = { loadstring = loadstring } diff --git a/moonscript/init.moon b/moonscript/init.moon index 61f15f8b..660c2f19 100644 --- a/moonscript/init.moon +++ b/moonscript/init.moon @@ -3,10 +3,9 @@ module "moonscript", package.seeall require "moonscript.compile" require "moonscript.parse" -require "moonscript.util" import concat, insert from table -import split, dump from util +import split, dump from require "moonscript.util" lua = :loadstring diff --git a/moonscript/types.lua b/moonscript/types.lua index d7b8897b..2cd4c0bd 100644 --- a/moonscript/types.lua +++ b/moonscript/types.lua @@ -1,14 +1,13 @@ -module("moonscript.types", package.seeall) local util = require("moonscript.util") local data = require("moonscript.data") local insert = table.insert -manual_return = data.Set({ +local manual_return = data.Set({ "foreach", "for", "while", "return" }) -cascading = data.Set({ +local cascading = data.Set({ "if", "unless", "with", @@ -16,6 +15,18 @@ cascading = data.Set({ "class", "do" }) +local ntype +ntype = function(node) + local _exp_0 = type(node) + if "nil" == _exp_0 then + return "nil" + elseif "table" == _exp_0 then + return node[1] + else + return "value" + end +end +local has_value has_value = function(node) if ntype(node) == "chain" then local ctype = ntype(node[#node]) @@ -24,26 +35,20 @@ has_value = function(node) return true end end +local is_value is_value = function(stm) local compile, transform = moonscript.compile, moonscript.transform return compile.Block:is_value(stm) or transform.Value:can_transform(stm) end +local comprehension_has_value comprehension_has_value = function(comp) return is_value(comp[2]) end -ntype = function(node) - local _exp_0 = type(node) - if "nil" == _exp_0 then - return "nil" - elseif "table" == _exp_0 then - return node[1] - else - return "value" - end -end +local value_is_singular value_is_singular = function(node) return type(node) ~= "table" or node[1] ~= "exp" or #node == 2 end +local is_slice is_slice = function(node) return ntype(node) == "chain" and ntype(node[#node]) == "slice" end @@ -183,7 +188,7 @@ make_builder = function(name) return node end end -build = nil +local build = nil build = setmetatable({ group = function(body) if body == nil then @@ -254,6 +259,7 @@ build = setmetatable({ return rawget(self, name) end }) +local smart_node smart_node = function(node) local index = key_table[ntype(node)] if not index then @@ -275,4 +281,15 @@ smart_node = function(node) end }) end -return nil +return { + ntype = ntype, + smart_node = smart_node, + build = build, + is_value = is_value, + is_slice = is_slice, + manual_return = manual_return, + cascading = cascading, + value_is_singular = value_is_singular, + comprehension_has_value = comprehension_has_value, + has_value = has_value +} diff --git a/moonscript/types.moon b/moonscript/types.moon index bdfd898c..72dc72f7 100644 --- a/moonscript/types.moon +++ b/moonscript/types.moon @@ -1,11 +1,7 @@ -module "moonscript.types", package.seeall + util = require "moonscript.util" data = require "moonscript.data" -export ntype, smart_node, build, is_value -export is_slice, manual_return, cascading, value_is_singular -export comprehension_has_value, has_value - import insert from table -- implicit return does not work on these statements @@ -16,6 +12,16 @@ manual_return = data.Set{"foreach", "for", "while", "return"} -- is the transformation to apply to the last statement in their body cascading = data.Set{ "if", "unless", "with", "switch", "class", "do" } +-- type of node as string +ntype = (node) -> + switch type node + when "nil" + "nil" + when "table" + node[1] + else + "value" + -- does this always return a value has_value = (node) -> if ntype(node) == "chain" @@ -31,16 +37,6 @@ is_value = (stm) -> comprehension_has_value = (comp) -> is_value comp[2] --- type of node as string -ntype = (node) -> - switch type node - when "nil" - "nil" - when "table" - node[1] - else - "value" - value_is_singular = (node) -> type(node) != "table" or node[1] != "exp" or #node == 2 @@ -160,4 +156,9 @@ smart_node = (node) -> rawset node, key, value } -nil + +{ + :ntype, :smart_node, :build, :is_value, :is_slice, :manual_return, + :cascading, :value_is_singular, :comprehension_has_value, :has_value +} + diff --git a/moonscript/util.lua b/moonscript/util.lua index 42531fa6..db429cd2 100644 --- a/moonscript/util.lua +++ b/moonscript/util.lua @@ -1,6 +1,5 @@ -module("moonscript.util", package.seeall) local concat = table.concat -moon = { +local moon = { is_object = function(value) return type(value) == "table" and value.__class end, @@ -15,6 +14,7 @@ moon = { return base_type end } +local pos_to_line pos_to_line = function(str, pos) local line = 1 for _ in str:sub(1, pos):gmatch("\n") do @@ -22,14 +22,11 @@ pos_to_line = function(str, pos) end return line end -get_closest_line = function(str, line_num) - local line = get_line(str, line_num) - if (not line or trim(line) == "") and line_num > 1 then - return get_closest_line(str, line_num - 1) - else - return line, line_num - end +local trim +trim = function(str) + return str:match("^%s*(.-)%s*$") end +local get_line get_line = function(str, line_num) for line in str:gmatch("([^\n]*)\n?") do if line_num == 1 then @@ -38,6 +35,16 @@ get_line = function(str, line_num) line_num = line_num - 1 end end +local get_closest_line +get_closest_line = function(str, line_num) + local line = get_line(str, line_num) + if (not line or trim(line) == "") and line_num > 1 then + return get_closest_line(str, line_num - 1) + else + return line, line_num + end +end +local reversed reversed = function(seq) return coroutine.wrap(function() for i = #seq, 1, -1 do @@ -45,9 +52,7 @@ reversed = function(seq) end end) end -trim = function(str) - return str:match("^%s*(.-)%s*$") -end +local split split = function(str, delim) if str == "" then return { } @@ -63,6 +68,7 @@ split = function(str, delim) return _accum_0 end)() end +local dump dump = function(what) local seen = { } local _dump @@ -99,6 +105,7 @@ dump = function(what) end return _dump(what) end +local debug_posmap debug_posmap = function(posmap, moon_code, lua_code) local tuples = (function() local _accum_0 = { } @@ -135,4 +142,14 @@ debug_posmap = function(posmap, moon_code, lua_code) end)() return concat(lines, "\n") end -return nil +return { + moon = moon, + pos_to_line = pos_to_line, + get_closest_line = get_closest_line, + get_line = get_line, + reversed = reversed, + trim = trim, + split = split, + dump = dump, + debug_posmap = debug_posmap +} diff --git a/moonscript/util.moon b/moonscript/util.moon index a7a9a765..b4ca9654 100644 --- a/moonscript/util.moon +++ b/moonscript/util.moon @@ -1,11 +1,4 @@ -module "moonscript.util", package.seeall - -export moon -export pos_to_line, get_closest_line, get_line -export reversed, trim, split -export dump, debug_posmap - import concat from table moon = @@ -25,12 +18,8 @@ pos_to_line = (str, pos) -> line += 1 line -get_closest_line = (str, line_num) -> - line = get_line str, line_num - if (not line or trim(line) == "") and line_num > 1 - get_closest_line(str, line_num - 1) - else - line, line_num +trim = (str) -> + str\match "^%s*(.-)%s*$" get_line = (str, line_num) -> -- todo: this returns an extra blank line at the end @@ -38,14 +27,18 @@ get_line = (str, line_num) -> return line if line_num == 1 line_num -= 1 +get_closest_line = (str, line_num) -> + line = get_line str, line_num + if (not line or trim(line) == "") and line_num > 1 + get_closest_line(str, line_num - 1) + else + line, line_num + reversed = (seq) -> coroutine.wrap -> for i=#seq,1,-1 coroutine.yield i, seq[i] -trim = (str) -> - str\match "^%s*(.-)%s*$" - split = (str, delim) -> return {} if str == "" str ..= delim @@ -90,5 +83,8 @@ debug_posmap = (posmap, moon_code, lua_code) -> concat(lines, "\n") -nil +{ + :moon, :pos_to_line, :get_closest_line, :get_line, :reversed, :trim, :split, + :dump, :debug_posmap +} diff --git a/test2.moon b/test2.moon index 40fecd73..aafca09f 100644 --- a/test2.moon +++ b/test2.moon @@ -2,11 +2,9 @@ require "lfs" require "busted" -require "moonscript.parse" -require "moonscript.compile" -require "moonscript.util" - -import parse, compile, util from moonscript +parse = require "moonscript.parse" +compile = require "moonscript.compile" +util = require "moonscript.util" pattern = ... From 38463a078d90b53fb7c8e0265bfe96e69b2d808a Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 28 Nov 2012 00:42:43 -0800 Subject: [PATCH 036/554] remove module from compile, reorganize --- bin/moonc | 2 +- moonscript/compile.lua | 37 ++++++++++++++++++++++--------- moonscript/compile.moon | 22 ++++++++---------- moonscript/compile/statement.lua | 15 ++++++++----- moonscript/compile/statement.moon | 14 ++++-------- moonscript/compile/value.lua | 6 +++-- moonscript/compile/value.moon | 10 ++++----- moonscript/init.lua | 2 +- moonscript/init.moon | 2 +- moonscript/types.lua | 3 ++- moonscript/types.moon | 4 +++- 11 files changed, 65 insertions(+), 52 deletions(-) diff --git a/bin/moonc b/bin/moonc index 5ed80aaa..1a1f4fea 100755 --- a/bin/moonc +++ b/bin/moonc @@ -3,7 +3,7 @@ module("moonscript", package.seeall) require "moonscript.parse" -require "moonscript.compile" +local compile = require "moonscript.compile" local util = require "moonscript.util" require "alt_getopt" diff --git a/moonscript/compile.lua b/moonscript/compile.lua index 9bfc282d..72f8ab33 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -1,8 +1,5 @@ -module("moonscript.compile", package.seeall) local util = require("moonscript.util") local dump = require("moonscript.dump") -require("moonscript.compile.statement") -require("moonscript.compile.value") local transform = require("moonscript.transform") local NameProxy, LocalName do @@ -19,11 +16,21 @@ do local _table_0 = require("moonscript.types") ntype, has_value = _table_0.ntype, _table_0.has_value end +local statement_compilers +do + local _table_0 = require("moonscript.compile.statement") + statement_compilers = _table_0.statement_compilers +end +local value_compilers +do + local _table_0 = require("moonscript.compile.value") + value_compilers = _table_0.value_compilers +end local concat, insert = table.concat, table.insert local pos_to_line, get_closest_line, trim = util.pos_to_line, util.get_closest_line, util.trim local mtype = util.moon.type local indent_char = " " -local Line, Lines +local Line, Lines, Block, RootBlock do local _parent_0 = nil local _base_0 = { @@ -160,7 +167,7 @@ do end local _list_0 = item for _index_0 = 1, #_list_0 do - value = _list_0[_index_0] + local value = _list_0[_index_0] self:_append_single(value) end else @@ -333,7 +340,7 @@ do self._name_whitelist = Set(names) end, put_name = function(self, name, ...) - value = ... + local value = ... if select("#", ...) == 0 then value = true end @@ -423,11 +430,11 @@ do end end, is_stm = function(self, node) - return line_compile[ntype(node)] ~= nil + return statement_compilers[ntype(node)] ~= nil end, is_value = function(self, node) local t = ntype(node) - return value_compile[t] ~= nil or t == "value" + return value_compilers[t] ~= nil or t == "value" end, name = function(self, node) return self:value(node) @@ -440,7 +447,7 @@ do else action = node[1] end - local fn = value_compile[action] + local fn = value_compilers[action] if not fn then error("Failed to compile value: " .. dump.value(node)) end @@ -482,7 +489,7 @@ do node = self.transform.statement(node) local result do - local fn = line_compile[ntype(node)] + local fn = statement_compilers[ntype(node)] if fn then result = fn(self, node, ...) else @@ -642,6 +649,7 @@ do end RootBlock = _class_0 end +local format_error format_error = function(msg, pos, file_str) local line = pos_to_line(file_str, pos) local line_str @@ -652,6 +660,7 @@ format_error = function(msg, pos, file_str) (" [%d] >> %s"):format(line, trim(line_str)) }, "\n") end +local value value = function(value) local out = nil do @@ -661,6 +670,7 @@ value = function(value) end return out end +local tree tree = function(tree, options) if options == nil then options = { } @@ -693,3 +703,10 @@ tree = function(tree, options) return lua_code, posmap end end +return { + tree = tree, + value = value, + format_error = format_error, + Block = Block, + RootBlock = RootBlock +} diff --git a/moonscript/compile.moon b/moonscript/compile.moon index 53994866..b2626443 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -1,17 +1,15 @@ -module "moonscript.compile", package.seeall util = require "moonscript.util" dump = require "moonscript.dump" - -require "moonscript.compile.statement" -require "moonscript.compile.value" - transform = require "moonscript.transform" import NameProxy, LocalName from require "moonscript.transform.names" import Set from require "moonscript.data" import ntype, has_value from require "moonscript.types" +import statement_compilers from require "moonscript.compile.statement" +import value_compilers from require "moonscript.compile.value" + import concat, insert from table import pos_to_line, get_closest_line, trim from util @@ -19,10 +17,7 @@ mtype = util.moon.type indent_char = " " -export tree, value, format_error -export Block, RootBlock - -local Line, Lines +local Line, Lines, Block, RootBlock -- a buffer for building up lines class Lines @@ -277,11 +272,11 @@ class Block \append ... is_stm: (node) => - line_compile[ntype node] != nil + statement_compilers[ntype node] != nil is_value: (node) => t = ntype node - value_compile[t] != nil or t == "value" + value_compilers[t] != nil or t == "value" -- line wise compile functions name: (node) => @value node @@ -292,7 +287,7 @@ class Block else node[1] - fn = value_compile[action] + fn = value_compilers[action] error "Failed to compile value: "..dump.value node if not fn out = fn self, node, ... @@ -314,7 +309,7 @@ class Block return if not node -- skip blank statements node = @transform.statement node - result = if fn = line_compile[ntype(node)] + result = if fn = statement_compilers[ntype(node)] fn self, node, ... else -- coerce value into statement @@ -399,3 +394,4 @@ tree = (tree, options={}) -> posmap = scope._lines\flatten_posmap! lua_code, posmap +{ :tree, :value, :format_error, :Block, :RootBlock } diff --git a/moonscript/compile/statement.lua b/moonscript/compile/statement.lua index fe7dd5b2..471364e6 100644 --- a/moonscript/compile/statement.lua +++ b/moonscript/compile/statement.lua @@ -1,15 +1,15 @@ -module("moonscript.compile", package.seeall) -local util = require("moonscript.util") -local dump = require("moonscript.dump") -local transform = require("moonscript.transform") -local reversed = util.reversed +local reversed +do + local _table_0 = require("moonscript.util") + reversed = _table_0.reversed +end local ntype do local _table_0 = require("moonscript.types") ntype = _table_0.ntype end local concat, insert = table.concat, table.insert -line_compile = { +local statement_compilers = { raw = function(self, node) return self:add(node[2]) end, @@ -246,3 +246,6 @@ line_compile = { end end } +return { + statement_compilers = statement_compilers +} diff --git a/moonscript/compile/statement.moon b/moonscript/compile/statement.moon index 59d6021d..4d687011 100644 --- a/moonscript/compile/statement.moon +++ b/moonscript/compile/statement.moon @@ -1,17 +1,9 @@ -module "moonscript.compile", package.seeall -util = require "moonscript.util" - -dump = require "moonscript.dump" -transform = require "moonscript.transform" - -import reversed from util +import reversed from require "moonscript.util" import ntype from require "moonscript.types" import concat, insert from table -export line_compile - -line_compile = +statement_compilers = raw: (node) => @add node[2] lines: (node) => @@ -139,3 +131,5 @@ line_compile = with @block! \stms node[2] + +{ :statement_compilers } diff --git a/moonscript/compile/value.lua b/moonscript/compile/value.lua index a6d9d549..3416ccc8 100644 --- a/moonscript/compile/value.lua +++ b/moonscript/compile/value.lua @@ -1,4 +1,3 @@ -module("moonscript.compile", package.seeall) local util = require("moonscript.util") local data = require("moonscript.data") local ntype @@ -13,7 +12,7 @@ do end local concat, insert = table.concat, table.insert local table_delim = "," -value_compile = { +local value_compilers = { exp = function(self, node) local _comp _comp = function(i, value) @@ -302,3 +301,6 @@ value_compile = { return tostring(value) end } +return { + value_compilers = value_compilers +} diff --git a/moonscript/compile/value.moon b/moonscript/compile/value.moon index a066c2f0..1087244d 100644 --- a/moonscript/compile/value.moon +++ b/moonscript/compile/value.moon @@ -1,19 +1,14 @@ -module "moonscript.compile", package.seeall - util = require "moonscript.util" data = require "moonscript.data" import ntype from require "moonscript.types" import user_error from require "moonscript.errors" - import concat, insert from table -export value_compile - table_delim = "," -value_compile = +value_compilers = -- list of values separated by binary operators exp: (node) => _comp = (i, value) -> @@ -189,3 +184,6 @@ value_compile = @send "varargs" tostring value + + +{ :value_compilers } diff --git a/moonscript/init.lua b/moonscript/init.lua index 61c65a41..b284adfc 100644 --- a/moonscript/init.lua +++ b/moonscript/init.lua @@ -1,5 +1,5 @@ module("moonscript", package.seeall) -require("moonscript.compile") +local compile = require("moonscript.compile") require("moonscript.parse") local concat, insert = table.concat, table.insert local split, dump diff --git a/moonscript/init.moon b/moonscript/init.moon index 660c2f19..34d4f9c4 100644 --- a/moonscript/init.moon +++ b/moonscript/init.moon @@ -1,7 +1,7 @@ module "moonscript", package.seeall -require "moonscript.compile" +compile = require "moonscript.compile" require "moonscript.parse" import concat, insert from table diff --git a/moonscript/types.lua b/moonscript/types.lua index 2cd4c0bd..e86b9b10 100644 --- a/moonscript/types.lua +++ b/moonscript/types.lua @@ -37,7 +37,8 @@ has_value = function(node) end local is_value is_value = function(stm) - local compile, transform = moonscript.compile, moonscript.transform + local compile = require("moonscript.compile") + local transform = require("moonscript.transform") return compile.Block:is_value(stm) or transform.Value:can_transform(stm) end local comprehension_has_value diff --git a/moonscript/types.moon b/moonscript/types.moon index 72dc72f7..6f25caed 100644 --- a/moonscript/types.moon +++ b/moonscript/types.moon @@ -31,7 +31,9 @@ has_value = (node) -> true is_value = (stm) -> - import compile, transform from moonscript + compile = require "moonscript.compile" + transform = require "moonscript.transform" + compile.Block\is_value(stm) or transform.Value\can_transform stm comprehension_has_value = (comp) -> From 915fc36b2ec81e04613be012125fc20e700e4c60 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 28 Nov 2012 20:53:47 -0800 Subject: [PATCH 037/554] convert more modules --- bin/moonc | 2 +- moonscript/init.lua | 2 +- moonscript/init.moon | 2 +- moonscript/parse.lua | 20 +++++++++++--------- moonscript/transform.lua | 11 ++++++++--- moonscript/transform.moon | 5 +---- test.lua | 5 ++--- 7 files changed, 25 insertions(+), 22 deletions(-) diff --git a/bin/moonc b/bin/moonc index 1a1f4fea..15cc49a0 100755 --- a/bin/moonc +++ b/bin/moonc @@ -2,7 +2,7 @@ module("moonscript", package.seeall) -require "moonscript.parse" +local parse = require "moonscript.parse" local compile = require "moonscript.compile" local util = require "moonscript.util" diff --git a/moonscript/init.lua b/moonscript/init.lua index b284adfc..17d9c487 100644 --- a/moonscript/init.lua +++ b/moonscript/init.lua @@ -1,6 +1,6 @@ module("moonscript", package.seeall) local compile = require("moonscript.compile") -require("moonscript.parse") +local parse = require("moonscript.parse") local concat, insert = table.concat, table.insert local split, dump do diff --git a/moonscript/init.moon b/moonscript/init.moon index 34d4f9c4..290a8a46 100644 --- a/moonscript/init.moon +++ b/moonscript/init.moon @@ -2,7 +2,7 @@ module "moonscript", package.seeall compile = require "moonscript.compile" -require "moonscript.parse" +parse = require "moonscript.parse" import concat, insert from table import split, dump from require "moonscript.util" diff --git a/moonscript/parse.lua b/moonscript/parse.lua index b706104f..fd409766 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -1,4 +1,3 @@ -module("moonscript.parse", package.seeall) local util = require"moonscript.util" @@ -117,7 +116,7 @@ local function wrap_env(fn) })) end -function extract_line(str, start_pos) +local function extract_line(str, start_pos) str = str:sub(start_pos) m = str:match"^(.-)\n" if m then return m end @@ -633,13 +632,16 @@ local build_grammar = wrap_env(function() return tree end } - end) --- parse a string --- returns tree, or nil and error message -function string(str) - local g = build_grammar() - return g:match(str) -end +return { + extract_line = extract_line, + + -- parse a string + -- returns tree, or nil and error message + string = function (str) + local g = build_grammar() + return g:match(str) + end +} diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 1039ad99..3d185f9b 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -1,4 +1,3 @@ -module("moonscript.transform", package.seeall) local types = require("moonscript.types") local util = require("moonscript.util") local data = require("moonscript.data") @@ -24,6 +23,7 @@ do end end local implicitly_return +local Run do local _parent_0 = nil local _base_0 = { @@ -335,7 +335,7 @@ construct_comprehension = function(inner, clauses) end return current_stms[1] end -Statement = Transformer({ +local Statement = Transformer({ root_stms = function(self, body) return apply_to_last(body, implicitly_return(self)) end, @@ -1309,7 +1309,7 @@ implicitly_return = function(scope) end return fn end -Value = Transformer({ +local Value = Transformer({ ["for"] = default_accumulator, ["while"] = default_accumulator, foreach = default_accumulator, @@ -1549,3 +1549,8 @@ Value = Transformer({ }) end }) +return { + Statement = Statement, + Value = Value, + Run = Run +} diff --git a/moonscript/transform.moon b/moonscript/transform.moon index c34035d8..1f865c25 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -1,6 +1,4 @@ -module "moonscript.transform", package.seeall - types = require "moonscript.types" util = require "moonscript.util" data = require "moonscript.data" @@ -22,8 +20,6 @@ mtype = do else t -export Statement, Value, Run - local implicitly_return class Run @@ -879,3 +875,4 @@ Value = Transformer { build.chain { base: {"parens", fn}, {"call", arg_list} } } +{ :Statement, :Value, :Run } diff --git a/test.lua b/test.lua index 073a4503..0b95e35b 100755 --- a/test.lua +++ b/test.lua @@ -10,9 +10,8 @@ pcall(function() gettime = socket.gettime end) -require "moonscript.parse" -require "moonscript.compile" -local parse, compile = moonscript.parse, moonscript.compile +parse = require "moonscript.parse" +compile = require "moonscript.compile" local opts, ind = alt_getopt.get_opts(arg, "qd:", { }) From ef2db0a1d5d519083ed52edc013215ad281384e0 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 28 Nov 2012 22:01:46 -0800 Subject: [PATCH 038/554] upate rockspec, add script --- gen_rockspec.sh | 7 +++++++ moonscript-dev-1.rockspec | 19 ++++++++++--------- 2 files changed, 17 insertions(+), 9 deletions(-) create mode 100755 gen_rockspec.sh diff --git a/gen_rockspec.sh b/gen_rockspec.sh new file mode 100755 index 00000000..b4faabd0 --- /dev/null +++ b/gen_rockspec.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +for file in $(find moonscript moon | grep 'lua$'); do + MODULE=$(echo $file | sed -e 's/\.lua$//' -e 's/\//./g' -e 's/\.init$//') + echo "[\"$MODULE\"] = \"$file\"," +done + diff --git a/moonscript-dev-1.rockspec b/moonscript-dev-1.rockspec index f1db90b2..9e191f13 100644 --- a/moonscript-dev-1.rockspec +++ b/moonscript-dev-1.rockspec @@ -22,21 +22,22 @@ dependencies = { build = { type = "builtin", modules = { - ["moonscript"] = "moonscript/init.lua", - ["moonscript.compile"] = "moonscript/compile.lua", - ["moonscript.compile.statement"] = "moonscript/compile/statement.lua", - ["moonscript.compile.value"] = "moonscript/compile/value.lua", - ["moonscript.compile.format"] = "moonscript/compile/format.lua", + ["moonscript.transform.destructure"] = "moonscript/transform/destructure.lua", + ["moonscript.transform.names"] = "moonscript/transform/names.lua", ["moonscript.transform"] = "moonscript/transform.lua", + ["moonscript.data"] = "moonscript/data.lua", + ["moonscript.version"] = "moonscript/version.lua", ["moonscript.types"] = "moonscript/types.lua", + ["moonscript.compile"] = "moonscript/compile.lua", ["moonscript.parse"] = "moonscript/parse.lua", - ["moonscript.dump"] = "moonscript/dump.lua", - ["moonscript.data"] = "moonscript/data.lua", ["moonscript.util"] = "moonscript/util.lua", + ["moonscript.dump"] = "moonscript/dump.lua", + ["moonscript.compile.statement"] = "moonscript/compile/statement.lua", + ["moonscript.compile.value"] = "moonscript/compile/value.lua", + ["moonscript"] = "moonscript/init.lua", ["moonscript.errors"] = "moonscript/errors.lua", - ["moonscript.version"] = "moonscript/version.lua", - ["moon"] = "moon/init.lua", ["moon.all"] = "moon/all.lua", + ["moon"] = "moon/init.lua", }, install = { bin = { "bin/moon", "bin/moonc" } From 7498a52aee9c75bbe72f64a166c0f35b31b19229 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 28 Nov 2012 22:47:52 -0800 Subject: [PATCH 039/554] sort tests --- test2.moon | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test2.moon b/test2.moon index aafca09f..2aee2a5e 100644 --- a/test2.moon +++ b/test2.moon @@ -81,6 +81,8 @@ output_fname = (base) -> describe "input tests", -> inputs = for file in lfs.dir options.in_dir file\match options.input_pattern + + table.sort inputs for name in *inputs input = input_fname name From 25b997e71fcf38b3012cf55b036419b767acc934 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 29 Nov 2012 00:37:49 -0800 Subject: [PATCH 040/554] allow destructure in for in names --- moonscript/parse.lua | 7 +++- moonscript/transform.lua | 42 ++++++++++++++------ moonscript/transform.moon | 25 ++++++------ moonscript/transform/destructure.lua | 37 +++++++++++------ moonscript/transform/destructure.moon | 19 ++++++--- moonscript/types.lua | 57 +++++++++++++++++---------- moonscript/types.moon | 46 ++++++++++++++------- tests/inputs/destructure.moon | 8 ++++ tests/outputs/destructure.lua | 16 ++++++++ 9 files changed, 179 insertions(+), 78 deletions(-) diff --git a/moonscript/parse.lua b/moonscript/parse.lua index fd409766..69d05925 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -435,7 +435,7 @@ local build_grammar = wrap_env(function() For = key"for" * DisableDo * ensure(Name * sym"=" * Ct(Exp * sym"," * Exp * (sym"," * Exp)^-1), PopDo) * key"do"^-1 * Body / mark"for", - ForEach = key"for" * Ct(NameList) * key"in" * DisableDo * ensure(Ct(sym"*" * Exp / mark"unpack" + ExpList), PopDo) * key"do"^-1 * Body / mark"foreach", + ForEach = key"for" * Ct(AssignableNameList) * key"in" * DisableDo * ensure(Ct(sym"*" * Exp / mark"unpack" + ExpList), PopDo) * key"do"^-1 * Body / mark"foreach", Do = key"do" * Body / mark"do", @@ -575,7 +575,7 @@ local build_grammar = wrap_env(function() (key"using" * Ct(NameList + Space * "nil") + Ct"") * sym")" + Ct"" * Ct"", - FnArgDefList = FnArgDef * (sym"," * FnArgDef)^0, + FnArgDefList = FnArgDef * (sym"," * FnArgDef)^0, FnArgDef = Ct(Name * (sym"=" * Exp)^-1), FunLit = FnArgsDef * @@ -583,6 +583,9 @@ local build_grammar = wrap_env(function() (Body + Ct"") / mark"fndef", NameList = Name * (sym"," * Name)^0, + NameOrDestructure = Name + TableLit, + AssignableNameList = NameOrDestructure * (sym"," * NameOrDestructure)^0, + ExpList = Exp * (sym"," * Exp)^0, ExpListLow = Exp * ((sym"," + sym";") * Exp)^0, diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 3d185f9b..925c426a 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -2,7 +2,7 @@ local types = require("moonscript.types") local util = require("moonscript.util") local data = require("moonscript.data") local reversed = util.reversed -local ntype, build, smart_node, is_slice, value_is_singular = types.ntype, types.build, types.smart_node, types.is_slice, types.value_is_singular +local ntype, mtype, build, smart_node, is_slice, value_is_singular = types.ntype, types.mtype, types.build, types.smart_node, types.is_slice, types.value_is_singular local insert = table.insert local NameProxy, LocalName do @@ -10,18 +10,6 @@ do NameProxy, LocalName = _table_0.NameProxy, _table_0.LocalName end local destructure = require("moonscript.transform.destructure") -local mtype -do - local moon_type = util.moon.type - mtype = function(val) - local t = type(val) - if "table" == t and rawget(val, "__class") then - return moon_type(val) - else - return t - end - end -end local implicitly_return local Run do @@ -670,6 +658,34 @@ local Statement = Transformer({ foreach = function(self, node) smart_node(node) local source = unpack(node.iter) + local destructures = { } + node.names = (function() + local _accum_0 = { } + local _len_0 = 0 + 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 + local extracted = destructure.extract_assign_names(name) + insert(destructures, destructure.build_assign(extracted, proxy)) + _value_0 = _with_0 + end + else + _value_0 = name + end + if _value_0 ~= nil then + _len_0 = _len_0 + 1 + _accum_0[_len_0] = _value_0 + end + end + return _accum_0 + end)() + if next(destructures) then + insert(destructures, build.group(node.body)) + node.body = destructures + end if ntype(source) == "unpack" then local list = source[2] local index_name = NameProxy("index") diff --git a/moonscript/transform.moon b/moonscript/transform.moon index 1f865c25..87687ed1 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -4,22 +4,12 @@ util = require "moonscript.util" data = require "moonscript.data" import reversed from util -import ntype, build, smart_node, is_slice, value_is_singular from types +import ntype, mtype, build, smart_node, is_slice, value_is_singular from types import insert from table import NameProxy, LocalName from require "moonscript.transform.names" destructure = require "moonscript.transform.destructure" -mtype = do - moon_type = util.moon.type - -- lets us check a smart node without throwing an error - (val) -> - t = type(val) - if "table" == t and rawget(val, "__class") - moon_type val - else - t - local implicitly_return class Run @@ -347,6 +337,19 @@ Statement = Transformer { smart_node node source = unpack node.iter + destructures = {} + node.names = for i, name in ipairs node.names + if ntype(name) == "table" + with proxy = NameProxy "des" + extracted = destructure.extract_assign_names name + insert destructures, destructure.build_assign extracted, proxy + else + name + + if next destructures + insert destructures, build.group node.body + node.body = destructures + if ntype(source) == "unpack" list = source[2] diff --git a/moonscript/transform/destructure.lua b/moonscript/transform/destructure.lua index 1c30c2cf..903bbcaa 100644 --- a/moonscript/transform/destructure.lua +++ b/moonscript/transform/destructure.lua @@ -1,7 +1,7 @@ -local ntype, build +local ntype, mtype, build do local _table_0 = require("moonscript.types") - ntype, build = _table_0.ntype, _table_0.build + ntype, mtype, build = _table_0.ntype, _table_0.mtype, _table_0.build end local NameProxy do @@ -48,9 +48,31 @@ has_destructure = function(names) end local build_assign build_assign = function(extracted_names, receiver) - local obj = NameProxy("obj") local names = { } local values = { } + local inner = { + "assign", + names, + values + } + local obj + if mtype(receiver) == NameProxy then + obj = receiver + else + do + local _with_0 = NameProxy("obj") + obj = _with_0 + inner = build["do"]({ + build.assign_one(obj, receiver), + { + "assign", + names, + values + } + }) + obj = _with_0 + end + end local _list_0 = extracted_names for _index_0 = 1, #_list_0 do local tuple = _list_0[_index_0] @@ -62,14 +84,7 @@ build_assign = function(extracted_names, receiver) "declare", names }, - build["do"]({ - build.assign_one(obj, receiver), - { - "assign", - names, - values - } - }) + inner }) end local extract_assign_names diff --git a/moonscript/transform/destructure.moon b/moonscript/transform/destructure.moon index 96525696..c39bea78 100644 --- a/moonscript/transform/destructure.moon +++ b/moonscript/transform/destructure.moon @@ -1,5 +1,5 @@ -import ntype, build from require "moonscript.types" +import ntype, mtype, build from require "moonscript.types" import NameProxy from require "moonscript.transform.names" import insert from table @@ -19,20 +19,27 @@ has_destructure = (names) -> false build_assign = (extracted_names, receiver) -> - obj = NameProxy "obj" names = {} values = {} + inner = {"assign", names, values} + + obj = if mtype(receiver) == NameProxy + receiver + else + with obj = NameProxy "obj" + inner = build.do { + build.assign_one obj, receiver + {"assign", names, values} + } + for tuple in *extracted_names insert names, tuple[1] insert values, obj\chain unpack tuple[2] build.group { {"declare", names} - build.do { - build.assign_one obj, receiver - {"assign", names, values} - } + inner } extract_assign_names = (name, accum={}, prefix={}) -> diff --git a/moonscript/types.lua b/moonscript/types.lua index e86b9b10..b145e208 100644 --- a/moonscript/types.lua +++ b/moonscript/types.lua @@ -26,6 +26,17 @@ ntype = function(node) return "value" end end +local mtype +do + local moon_type = util.moon.type + mtype = function(val) + local mt = getmetatable(val) + if mt and mt.smart_node then + return "table" + end + return moon_type(val) + end +end local has_value has_value = function(node) if ntype(node) == "chain" then @@ -260,27 +271,32 @@ build = setmetatable({ return rawget(self, name) end }) +local smart_node_mt = setmetatable({ }, { + __index = function(self, node_type) + local index = key_table[node_type] + local mt = { + smart_node = true, + __index = function(node, key) + if index[key] then + return rawget(node, index[key]) + elseif type(key) == "string" then + return error("unknown key: `" .. key .. "` on node type: `" .. ntype(node) .. "`") + end + end, + __newindex = function(node, key, value) + if index[key] then + key = index[key] + end + return rawset(node, key, value) + end + } + self[node_type] = mt + return mt + end +}) local smart_node smart_node = function(node) - local index = key_table[ntype(node)] - if not index then - return node - end - return setmetatable(node, { - __index = function(node, key) - if index[key] then - return rawget(node, index[key]) - elseif type(key) == "string" then - return error("unknown key: `" .. key .. "` on node type: `" .. ntype(node) .. "`") - end - end, - __newindex = function(node, key, value) - if index[key] then - key = index[key] - end - return rawset(node, key, value) - end - }) + return setmetatable(node, smart_node_mt[ntype(node)]) end return { ntype = ntype, @@ -292,5 +308,6 @@ return { cascading = cascading, value_is_singular = value_is_singular, comprehension_has_value = comprehension_has_value, - has_value = has_value + has_value = has_value, + mtype = mtype } diff --git a/moonscript/types.moon b/moonscript/types.moon index 6f25caed..c6df7f41 100644 --- a/moonscript/types.moon +++ b/moonscript/types.moon @@ -22,6 +22,14 @@ ntype = (node) -> else "value" +mtype = do + moon_type = util.moon.type + -- lets us check a smart node without throwing an error + (val) -> + mt = getmetatable val + return "table" if mt and mt.smart_node + moon_type val + -- does this always return a value has_value = (node) -> if ntype(node) == "chain" @@ -142,25 +150,33 @@ build = setmetatable { rawget self, name } +smart_node_mt = setmetatable {}, { + __index: (node_type) => + index = key_table[node_type] + mt = { + smart_node: true + + __index: (node, key) -> + if index[key] + rawget node, index[key] + elseif type(key) == "string" + error "unknown key: `"..key.."` on node type: `"..ntype(node).. "`" + + __newindex: (node, key, value) -> + key = index[key] if index[key] + rawset node, key, value + } + self[node_type] = mt + mt +} + -- makes it so node properties can be accessed by name instead of index smart_node = (node) -> - index = key_table[ntype node] - if not index then return node - setmetatable node, { - __index: (node, key) -> - if index[key] - rawget node, index[key] - elseif type(key) == "string" - error "unknown key: `"..key.."` on node type: `"..ntype(node).. "`" - - __newindex: (node, key, value) -> - key = index[key] if index[key] - rawset node, key, value - } - + setmetatable node, smart_node_mt[ntype node] { :ntype, :smart_node, :build, :is_value, :is_slice, :manual_return, - :cascading, :value_is_singular, :comprehension_has_value, :has_value + :cascading, :value_is_singular, :comprehension_has_value, :has_value, + :mtype } diff --git a/tests/inputs/destructure.moon b/tests/inputs/destructure.moon index 847ae730..561f229b 100644 --- a/tests/inputs/destructure.moon +++ b/tests/inputs/destructure.moon @@ -43,3 +43,11 @@ print name, street, city { world: @world } = x +-- + +thing = {{1,2}, {3,4}} + +for {x,y} in *thing + print x,y + + diff --git a/tests/outputs/destructure.lua b/tests/outputs/destructure.lua index 9299b724..bb99e753 100644 --- a/tests/outputs/destructure.lua +++ b/tests/outputs/destructure.lua @@ -85,4 +85,20 @@ end do local _obj_0 = x self.world = _obj_0.world +end +thing = { + { + 1, + 2 + }, + { + 3, + 4 + } +} +local _list_0 = thing +for _index_0 = 1, #_list_0 do + local _des_0 = _list_0[_index_0] + x, y = _des_0[1], _des_0[2] + print(x, y) end \ No newline at end of file From 252e875833f50c7fdea8842bda1cff08df0cc4ad Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 29 Nov 2012 01:05:22 -0800 Subject: [PATCH 041/554] allow multiple name proxy of same type in names of for in loop --- moonscript/compile.lua | 4 ++-- moonscript/compile.moon | 3 ++- moonscript/compile/statement.lua | 18 +++++++++--------- moonscript/compile/statement.moon | 9 +++++---- moonscript/compile/value.lua | 4 ++-- moonscript/compile/value.moon | 4 ++-- moonscript/transform/names.lua | 7 +++++-- moonscript/transform/names.moon | 4 ++-- 8 files changed, 29 insertions(+), 24 deletions(-) diff --git a/moonscript/compile.lua b/moonscript/compile.lua index 72f8ab33..e0128424 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -436,8 +436,8 @@ do local t = ntype(node) return value_compilers[t] ~= nil or t == "value" end, - name = function(self, node) - return self:value(node) + name = function(self, node, ...) + return self:value(node, ...) end, value = function(self, node, ...) node = self.transform.value(node) diff --git a/moonscript/compile.moon b/moonscript/compile.moon index b2626443..c289b6aa 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -279,7 +279,8 @@ class Block value_compilers[t] != nil or t == "value" -- line wise compile functions - name: (node) => @value node + name: (node, ...) => @value node, ... + value: (node, ...) => node = @transform.value node action = if type(node) != "table" diff --git a/moonscript/compile/statement.lua b/moonscript/compile/statement.lua index 471364e6..4c8ae3eb 100644 --- a/moonscript/compile/statement.lua +++ b/moonscript/compile/statement.lua @@ -185,19 +185,23 @@ local statement_compilers = { do local _with_0 = self:line() _with_0:append("for ") - _with_0:append_list((function() + loop = _with_0 + end + do + local _with_0 = self:block(loop) + loop:append_list((function() local _accum_0 = { } local _len_0 = 0 local _list_0 = names for _index_0 = 1, #_list_0 do local name = _list_0[_index_0] _len_0 = _len_0 + 1 - _accum_0[_len_0] = self:name(name) + _accum_0[_len_0] = _with_0:name(name, false) end return _accum_0 end)(), ", ") - _with_0:append(" in ") - _with_0:append_list((function() + loop:append(" in ") + loop:append_list((function() local _accum_0 = { } local _len_0 = 0 local _list_0 = exps @@ -208,11 +212,7 @@ local statement_compilers = { end return _accum_0 end)(), ",") - _with_0:append(" do") - loop = _with_0 - end - do - local _with_0 = self:block(loop) + loop:append(" do") _with_0:declare(names) _with_0:stms(block) return _with_0 diff --git a/moonscript/compile/statement.moon b/moonscript/compile/statement.moon index 4d687011..d390186a 100644 --- a/moonscript/compile/statement.moon +++ b/moonscript/compile/statement.moon @@ -100,12 +100,13 @@ statement_compilers = loop = with @line! \append "for " - \append_list [@name name for name in *names], ", " - \append " in " - \append_list [@value exp for exp in *exps], "," - \append " do" with @block loop + loop\append_list [\name name, false for name in *names], ", " + loop\append " in " + loop\append_list [@value exp for exp in *exps], "," + loop\append " do" + \declare names \stms block diff --git a/moonscript/compile/value.lua b/moonscript/compile/value.lua index 3416ccc8..7f9c30bf 100644 --- a/moonscript/compile/value.lua +++ b/moonscript/compile/value.lua @@ -266,8 +266,8 @@ local value_compilers = { minus = function(self, node) return self:line("-", self:value(node[2])) end, - temp_name = function(self, node) - return node:get_name(self) + temp_name = function(self, node, ...) + return node:get_name(self, ...) end, number = function(self, node) return node[2] diff --git a/moonscript/compile/value.moon b/moonscript/compile/value.moon index 1087244d..87e47141 100644 --- a/moonscript/compile/value.moon +++ b/moonscript/compile/value.moon @@ -150,8 +150,8 @@ value_compilers = minus: (node) => @line "-", @value node[2] - temp_name: (node) => - node\get_name self + temp_name: (node, ...) => + node\get_name self, ... number: (node) => node[2] diff --git a/moonscript/transform/names.lua b/moonscript/transform/names.lua index aa28dcdc..4eb294d6 100644 --- a/moonscript/transform/names.lua +++ b/moonscript/transform/names.lua @@ -48,9 +48,12 @@ local NameProxy do local _parent_0 = nil local _base_0 = { - get_name = function(self, scope) + get_name = function(self, scope, dont_put) + if dont_put == nil then + dont_put = true + end if not self.name then - self.name = scope:free_name(self.prefix, true) + self.name = scope:free_name(self.prefix, dont_put) end return self.name end, diff --git a/moonscript/transform/names.moon b/moonscript/transform/names.moon index f5059971..79a2b00d 100644 --- a/moonscript/transform/names.moon +++ b/moonscript/transform/names.moon @@ -11,9 +11,9 @@ class NameProxy new: (@prefix) => self[1] = "temp_name" - get_name: (scope) => + get_name: (scope, dont_put=true) => if not @name - @name = scope\free_name @prefix, true + @name = scope\free_name @prefix, dont_put @name chain: (...) => From 5162082085343b14ee7d38996b032401176d817d Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 29 Nov 2012 09:19:35 -0800 Subject: [PATCH 042/554] allow multiple cases per when statement in switch also fix precedence issue when using lower than == precedence operators in when --- moonscript/parse.lua | 2 +- moonscript/transform.lua | 23 ++++++++++++++++++----- moonscript/transform.moon | 16 +++++++++++++--- tests/inputs/switch.moon | 20 ++++++++++++++++++++ tests/outputs/switch.lua | 24 +++++++++++++++++++++--- 5 files changed, 73 insertions(+), 12 deletions(-) diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 69d05925..808920eb 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -418,7 +418,7 @@ local build_grammar = wrap_env(function() Switch = key"switch" * DisableDo * ensure(Exp, PopDo) * key"do"^-1 * Space^-1 * Break * SwitchBlock / mark"switch", SwitchBlock = EmptyLine^0 * Advance * Ct(SwitchCase * (Break^1 * SwitchCase)^0 * (Break^1 * SwitchElse)^-1) * PopIndent, - SwitchCase = key"when" * Exp * key"then"^-1 * Body / mark"case", + SwitchCase = key"when" * Ct(ExpList) * key"then"^-1 * Body / mark"case", SwitchElse = key"else" * Body / mark"else", IfCond = Exp * Assign^-1 / format_single_assign, diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 925c426a..5bb4ec48 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -764,20 +764,33 @@ local Statement = Transformer({ local exp_name = NameProxy("exp") local convert_cond convert_cond = function(cond) - local t, case_exp, body = unpack(cond) + local t, case_exps, body = unpack(cond) local out = { } insert(out, t == "case" and "elseif" or "else") if t ~= "else" then - if t ~= "else" then - insert(out, { + local cond_exp = { } + for i, case in ipairs(case_exps) do + if i == 1 then + insert(cond_exp, "exp") + else + insert(cond_exp, "or") + end + if not (value_is_singular(case)) then + case = { + "parens", + case + } + end + insert(cond_exp, { "exp", - case_exp, + case, "==", exp_name }) end + insert(out, cond_exp) else - body = case_exp + body = case_exps end if ret then body = apply_to_last(body, ret) diff --git a/moonscript/transform.moon b/moonscript/transform.moon index 87687ed1..8f5dad3f 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -404,13 +404,23 @@ Statement = Transformer { -- convert switch conds into if statment conds convert_cond = (cond) -> - t, case_exp, body = unpack cond + t, case_exps, body = unpack cond out = {} insert out, t == "case" and "elseif" or "else" if t != "else" - insert out, {"exp", case_exp, "==", exp_name} if t != "else" + cond_exp = {} + for i, case in ipairs case_exps + if i == 1 + insert cond_exp, "exp" + else + insert cond_exp, "or" + + case = {"parens", case} unless value_is_singular case + insert cond_exp, {"exp", case, "==", exp_name} + + insert out, cond_exp else - body = case_exp + body = case_exps if ret body = apply_to_last body, ret diff --git a/tests/inputs/switch.moon b/tests/inputs/switch.moon index abb1b97c..3bc179b3 100644 --- a/tests/inputs/switch.moon +++ b/tests/inputs/switch.moon @@ -42,3 +42,23 @@ call_func switch something when 1 then "yes" else "no" +-- + +switch hi + when hello or world + greene + +-- + +switch hi + when "one", "two" + print "cool" + when "dad" + no + +switch hi + when 3+1, hello!, (-> 4)! + yello + else + print "cool" + diff --git a/tests/outputs/switch.lua b/tests/outputs/switch.lua index 96cc1042..764c530f 100644 --- a/tests/outputs/switch.lua +++ b/tests/outputs/switch.lua @@ -13,7 +13,7 @@ if "cool" == _exp_2 then print("hello world") elseif "yeah" == _exp_2 then local _ = [[FFFF]] + [[MMMM]] -elseif 2323 + 32434 == _exp_2 then +elseif (2323 + 32434) == _exp_2 then print("okay") else print("okay rad") @@ -43,11 +43,29 @@ do end end fix(this) -return call_func((function() +call_func((function() local _exp_5 = something if 1 == _exp_5 then return "yes" else return "no" end -end)()) \ No newline at end of file +end)()) +local _exp_5 = hi +if (hello or world) == _exp_5 then + local _ = greene +end +local _exp_6 = hi +if "one" == _exp_6 or "two" == _exp_6 then + print("cool") +elseif "dad" == _exp_6 then + local _ = no +end +local _exp_7 = hi +if (3 + 1) == _exp_7 or hello() == _exp_7 or (function() + return 4 +end)() == _exp_7 then + return yello +else + return print("cool") +end \ No newline at end of file From 181e06d9ae423d6005a2ba155d896d14778a134a Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 29 Nov 2012 09:48:08 -0800 Subject: [PATCH 043/554] destructure works with if assignment cond --- moonscript/transform.lua | 36 ++++++++--- moonscript/transform.moon | 26 +++++--- moonscript/transform/destructure.lua | 87 +++++++++++++-------------- moonscript/transform/destructure.moon | 55 ++++++++--------- tests/inputs/destructure.moon | 25 ++++++++ tests/outputs/destructure.lua | 43 +++++++++++++ todo | 12 ++-- 7 files changed, 190 insertions(+), 94 deletions(-) diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 5bb4ec48..47444e89 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -602,15 +602,32 @@ local Statement = Transformer({ ["if"] = function(self, node, ret) if ntype(node[2]) == "assign" then local _, assign, body = unpack(node) - local name = assign[2][1] - return build["do"]({ - assign, - { - "if", - name, - unpack(node, 3) + if destructure.has_destructure(assign[2]) then + local name = NameProxy("des") + body = { + destructure.build_assign(assign[2][1], name), + build.group(node[3]) } - }) + return build["do"]({ + build.assign_one(name, assign[3][1]), + { + "if", + name, + body, + unpack(node, 4) + } + }) + else + local name = assign[2][1] + return build["do"]({ + assign, + { + "if", + name, + unpack(node, 3) + } + }) + end end node = expand_elseif_assign(node) if ret then @@ -668,8 +685,7 @@ local Statement = Transformer({ do local _with_0 = NameProxy("des") local proxy = _with_0 - local extracted = destructure.extract_assign_names(name) - insert(destructures, destructure.build_assign(extracted, proxy)) + insert(destructures, destructure.build_assign(name, proxy)) _value_0 = _with_0 end else diff --git a/moonscript/transform.moon b/moonscript/transform.moon index 8f5dad3f..067845ee 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -291,11 +291,24 @@ Statement = Transformer { -- expand assign in cond if ntype(node[2]) == "assign" _, assign, body = unpack node - name = assign[2][1] - return build["do"] { - assign - {"if", name, unpack node, 3} - } + if destructure.has_destructure assign[2] + name = NameProxy "des" + + body = { + destructure.build_assign assign[2][1], name + build.group node[3] + } + + return build.do { + build.assign_one name, assign[3][1] + {"if", name, body, unpack node, 4} + } + else + name = assign[2][1] + return build["do"] { + assign + {"if", name, unpack node, 3} + } node = expand_elseif_assign node @@ -341,8 +354,7 @@ Statement = Transformer { node.names = for i, name in ipairs node.names if ntype(name) == "table" with proxy = NameProxy "des" - extracted = destructure.extract_assign_names name - insert destructures, destructure.build_assign extracted, proxy + insert destructures, destructure.build_assign name, proxy else name diff --git a/moonscript/transform/destructure.lua b/moonscript/transform/destructure.lua index 903bbcaa..ca9fdace 100644 --- a/moonscript/transform/destructure.lua +++ b/moonscript/transform/destructure.lua @@ -46,47 +46,6 @@ has_destructure = function(names) end return false end -local build_assign -build_assign = function(extracted_names, receiver) - local names = { } - local values = { } - local inner = { - "assign", - names, - values - } - local obj - if mtype(receiver) == NameProxy then - obj = receiver - else - do - local _with_0 = NameProxy("obj") - obj = _with_0 - inner = build["do"]({ - build.assign_one(obj, receiver), - { - "assign", - names, - values - } - }) - obj = _with_0 - end - end - local _list_0 = extracted_names - for _index_0 = 1, #_list_0 do - local tuple = _list_0[_index_0] - insert(names, tuple[1]) - insert(values, obj:chain(unpack(tuple[2]))) - end - return build.group({ - { - "declare", - names - }, - inner - }) -end local extract_assign_names extract_assign_names = function(name, accum, prefix) if accum == nil then @@ -143,6 +102,48 @@ extract_assign_names = function(name, accum, prefix) end return accum end +local build_assign +build_assign = function(destruct_literal, receiver) + local extracted_names = extract_assign_names(destruct_literal) + local names = { } + local values = { } + local inner = { + "assign", + names, + values + } + local obj + if mtype(receiver) == NameProxy then + obj = receiver + else + do + local _with_0 = NameProxy("obj") + obj = _with_0 + inner = build["do"]({ + build.assign_one(obj, receiver), + { + "assign", + names, + values + } + }) + obj = _with_0 + end + end + local _list_0 = extracted_names + for _index_0 = 1, #_list_0 do + local tuple = _list_0[_index_0] + insert(names, tuple[1]) + insert(values, obj:chain(unpack(tuple[2]))) + end + return build.group({ + { + "declare", + names + }, + inner + }) +end local split_assign split_assign = function(assign) local names, values = unpack(assign, 2) @@ -182,8 +183,7 @@ split_assign = function(assign) end)() }) end - local extracted = extract_assign_names(n) - insert(g, build_assign(extracted, values[i])) + insert(g, build_assign(n, values[i])) start = i + 1 end end @@ -237,6 +237,5 @@ end return { has_destructure = has_destructure, split_assign = split_assign, - extract_assign_names = extract_assign_names, build_assign = build_assign } diff --git a/moonscript/transform/destructure.moon b/moonscript/transform/destructure.moon index c39bea78..7d73f4d6 100644 --- a/moonscript/transform/destructure.moon +++ b/moonscript/transform/destructure.moon @@ -18,30 +18,6 @@ has_destructure = (names) -> return true if ntype(n) == "table" false -build_assign = (extracted_names, receiver) -> - names = {} - values = {} - - inner = {"assign", names, values} - - obj = if mtype(receiver) == NameProxy - receiver - else - with obj = NameProxy "obj" - inner = build.do { - build.assign_one obj, receiver - {"assign", names, values} - } - - for tuple in *extracted_names - insert names, tuple[1] - insert values, obj\chain unpack tuple[2] - - build.group { - {"declare", names} - inner - } - extract_assign_names = (name, accum={}, prefix={}) -> i = 1 for tuple in *name[2] @@ -70,6 +46,32 @@ extract_assign_names = (name, accum={}, prefix={}) -> accum +build_assign = (destruct_literal, receiver) -> + extracted_names = extract_assign_names destruct_literal + + names = {} + values = {} + + inner = {"assign", names, values} + + obj = if mtype(receiver) == NameProxy + receiver + else + with obj = NameProxy "obj" + inner = build.do { + build.assign_one obj, receiver + {"assign", names, values} + } + + for tuple in *extracted_names + insert names, tuple[1] + insert values, obj\chain unpack tuple[2] + + build.group { + {"declare", names} + inner + } + -- applies to destructuring to a assign node split_assign = (assign) -> names, values = unpack assign, 2 @@ -93,8 +95,7 @@ split_assign = (assign) -> values[i] } - extracted = extract_assign_names n - insert g, build_assign extracted, values[i] + insert g, build_assign n, values[i] start = i + 1 @@ -113,4 +114,4 @@ split_assign = (assign) -> build.group g -{ :has_destructure, :split_assign, :extract_assign_names, :build_assign } +{ :has_destructure, :split_assign, :build_assign } diff --git a/tests/inputs/destructure.moon b/tests/inputs/destructure.moon index 561f229b..e0118345 100644 --- a/tests/inputs/destructure.moon +++ b/tests/inputs/destructure.moon @@ -51,3 +51,28 @@ for {x,y} in *thing print x,y +-- + +with {a,b} = thing + print a, b + + +-- + +thing = nil +if {a} = thing + print a +else + print "nothing" + +thang = {1,2} +if {a,b} = thang + print a,b + +if {a,b} = thing + print a,b +elseif {c,d} = thang + print c,d +else + print "NO" + diff --git a/tests/outputs/destructure.lua b/tests/outputs/destructure.lua index bb99e753..b2da4c3f 100644 --- a/tests/outputs/destructure.lua +++ b/tests/outputs/destructure.lua @@ -101,4 +101,47 @@ for _index_0 = 1, #_list_0 do local _des_0 = _list_0[_index_0] x, y = _des_0[1], _des_0[2] print(x, y) +end +do + local _with_0 = thing + a, b = _with_0[1], _with_0[2] + print(a, b) +end +thing = nil +do + local _des_0 = thing + if _des_0 then + a = _des_0[1] + print(a) + else + print("nothing") + end +end +local thang = { + 1, + 2 +} +do + local _des_0 = thang + if _des_0 then + a, b = _des_0[1], _des_0[2] + print(a, b) + end +end +do + local _des_0 = thing + if _des_0 then + a, b = _des_0[1], _des_0[2] + print(a, b) + else + do + local _des_1 = thang + if _des_1 then + c, d = _des_1[1], _des_1[2] + print(c, d) + else + return print("NO") + end + end + end end \ No newline at end of file diff --git a/todo b/todo index 07952e39..ae5ecb94 100644 --- a/todo +++ b/todo @@ -1,4 +1,9 @@ # TODO +# +# +# + +-- local * and local ^ -- seems like running in moon messes up require order @@ -8,19 +13,14 @@ - or= and= -- a do block for making a quick anon func and calling it - - error with stray comma at end of line -- ugly error if attempting to assign to rvalue like #hello - -- class expressions, x = class extends Hello do new: => print "hello" * multiline comments * table slices (almost) * combine for and if line decorators -* export later? +* export later? nah x = 232 export x From 59333513c23bfe3cc11541a79ba3e9a3385265b9 Mon Sep 17 00:00:00 2001 From: leaf Date: Wed, 26 Dec 2012 16:29:46 -0800 Subject: [PATCH 044/554] update links to scintillua --- extra/scintillua/README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/extra/scintillua/README.md b/extra/scintillua/README.md index 7bb850bf..ffeb9800 100644 --- a/extra/scintillua/README.md +++ b/extra/scintillua/README.md @@ -1,4 +1,3 @@ - # MoonScript for [scintillua][1] MoonScript syntax file for [SciTE][2] written in Lua for [scintillua][1]. @@ -14,7 +13,7 @@ the directions below. ## Installation -Install SciTE, then [install scintillua][3]. +Install SciTE, then [install scintillua][1]. Put `moonscript.properties` in in your ScITE installation folder or user properties folder. @@ -32,6 +31,6 @@ file and change it to: lexer.lpeg.color.theme=moon - [1]: http://code.google.com/p/scintillua/ "scintillua" + [1]: http://foicica.com/scintillua/ "scintillua" [2]: http://www.scintilla.org/SciTE.html "SciTE" - [3]: http://code.google.com/p/scintillua/#Using_with_SciTE \ No newline at end of file + From e99161359a60624ccc953f203c407f666db9c3ff Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 2 Jan 2013 12:57:40 -0800 Subject: [PATCH 045/554] setfenv and getfenv for lua 5.2 --- moonscript/util.lua | 35 ++++++++++++++++++++++++++++++++++- moonscript/util.moon | 24 +++++++++++++++++++++++- 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/moonscript/util.lua b/moonscript/util.lua index db429cd2..47ed3908 100644 --- a/moonscript/util.lua +++ b/moonscript/util.lua @@ -142,6 +142,37 @@ debug_posmap = function(posmap, moon_code, lua_code) end)() return concat(lines, "\n") end +local setfenv = setfenv or function(fn, env) + local name + local i = 1 + while true do + name = debug.getupvalue(fn, i) + if not name or name == "_ENV" then + break + end + i = i + 1 + end + if name then + debug.upvaluejoin(fn, i, (function() + return env + end), 1) + end + return fn +end +local getfenv = getfenv or function(fn) + local i = 1 + while true do + local name, val = debug.getupvalue(fn, i) + if not (name) then + break + end + if name == "_ENV" then + return val + end + i = i + 1 + end + return nil +end return { moon = moon, pos_to_line = pos_to_line, @@ -151,5 +182,7 @@ return { trim = trim, split = split, dump = dump, - debug_posmap = debug_posmap + debug_posmap = debug_posmap, + getfenv = getfenv, + setfenv = setfenv } diff --git a/moonscript/util.moon b/moonscript/util.moon index b4ca9654..65fcaaeb 100644 --- a/moonscript/util.moon +++ b/moonscript/util.moon @@ -83,8 +83,30 @@ debug_posmap = (posmap, moon_code, lua_code) -> concat(lines, "\n") +setfenv = setfenv or (fn, env) -> + local name + i = 1 + while true + name = debug.getupvalue fn, i + break if not name or name == "_ENV" + i += 1 + + if name + debug.upvaluejoin fn, i, (-> env), 1 + + fn + +getfenv = getfenv or (fn) -> + i = 1 + while true + name, val = debug.getupvalue fn, i + break unless name + return val if name == "_ENV" + i += 1 + nil + { :moon, :pos_to_line, :get_closest_line, :get_line, :reversed, :trim, :split, - :dump, :debug_posmap + :dump, :debug_posmap, :getfenv, :setfenv } From 1f8b54da3c5f1dfd8caa4b29c52c889fc94cb735 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 2 Jan 2013 13:53:31 -0800 Subject: [PATCH 046/554] lua 5.2 support --- moonscript/errors.lua | 5 ++--- moonscript/errors.moon | 5 ++--- moonscript/init.lua | 20 +++++++++++++++++--- moonscript/init.moon | 13 +++++++------ moonscript/line_tables.lua | 1 + moonscript/line_tables.moon | 1 + moonscript/parse.lua | 5 ++++- 7 files changed, 34 insertions(+), 16 deletions(-) create mode 100644 moonscript/line_tables.lua create mode 100644 moonscript/line_tables.moon diff --git a/moonscript/errors.lua b/moonscript/errors.lua index 3e5b9e25..d163d729 100644 --- a/moonscript/errors.lua +++ b/moonscript/errors.lua @@ -1,6 +1,5 @@ -local moon = require("moonscript") local util = require("moonscript.util") -require("lpeg") +local lpeg = require("lpeg") local concat, insert = table.concat, table.insert local split, pos_to_line = util.split, util.pos_to_line local user_error @@ -61,7 +60,7 @@ truncate_traceback = function(traceback, chunk_func) end local rewrite_traceback rewrite_traceback = function(text, err) - local line_tables = moon.line_tables + local line_tables = require("moonscript.line_tables") local V, S, Ct, C = lpeg.V, lpeg.S, lpeg.Ct, lpeg.C local header_text = "stack traceback:" local Header, Line = V("Header"), V("Line") diff --git a/moonscript/errors.moon b/moonscript/errors.moon index f077ccd5..c74f69df 100644 --- a/moonscript/errors.moon +++ b/moonscript/errors.moon @@ -1,8 +1,7 @@ -moon = require "moonscript" util = require "moonscript.util" -require "lpeg" +lpeg = require "lpeg" import concat, insert from table import split, pos_to_line from util @@ -43,7 +42,7 @@ truncate_traceback = (traceback, chunk_func="moonscript_chunk") -> concat traceback, "\n" rewrite_traceback = (text, err) -> - line_tables = moon.line_tables + line_tables = require "moonscript.line_tables" import V, S, Ct, C from lpeg header_text = "stack traceback:" diff --git a/moonscript/init.lua b/moonscript/init.lua index 17d9c487..8ea4560c 100644 --- a/moonscript/init.lua +++ b/moonscript/init.lua @@ -1,4 +1,3 @@ -module("moonscript", package.seeall) local compile = require("moonscript.compile") local parse = require("moonscript.parse") local concat, insert = table.concat, table.insert @@ -10,8 +9,8 @@ end local lua = { loadstring = loadstring } -dirsep = "/" -line_tables = { } +local dirsep = "/" +local line_tables = require("moonscript.line_tables") local create_moonpath create_moonpath = function(package_path) local paths = split(package_path, ";") @@ -23,6 +22,7 @@ create_moonpath = function(package_path) end return concat(paths, ";") end +local to_lua to_lua = function(text, options) if options == nil then options = { } @@ -41,6 +41,7 @@ to_lua = function(text, options) end return code, ltable end +local moon_loader moon_loader = function(name) local name_path = name:gsub("%.", dirsep) local file, file_path = nil, nil @@ -71,6 +72,7 @@ end if not _G.moon_no_loader then init_loader() end +local loadstring loadstring = function(str, chunk_name, options) if options == nil then options = nil @@ -86,6 +88,7 @@ loadstring = function(str, chunk_name, options) end return lua.loadstring(code, chunk_name or "=(moonscript.loadstring)") end +local loadfile loadfile = function(fname, options) if options == nil then options = nil @@ -98,7 +101,18 @@ loadfile = function(fname, options) file:close() return loadstring(text, fname, options) end +local dofile dofile = function(fname, options) local f = assert(loadfile(fname)) return f() end +return { + _NAME = "moonscript", + to_lua = to_lua, + moon_chunk = moon_chunk, + moon_loader = moon_loader, + dirsep = dirsep, + dofile = dofile, + loadfile = loadfile, + loadstring = loadstring +} diff --git a/moonscript/init.moon b/moonscript/init.moon index 290a8a46..260c88fb 100644 --- a/moonscript/init.moon +++ b/moonscript/init.moon @@ -1,6 +1,4 @@ -module "moonscript", package.seeall - compile = require "moonscript.compile" parse = require "moonscript.parse" @@ -9,11 +7,8 @@ import split, dump from require "moonscript.util" lua = :loadstring -export to_lua, moon_chunk, moon_loader, dirsep, line_tables -export dofile, loadfile, loadstring - dirsep = "/" -line_tables = {} +line_tables = require "moonscript.line_tables" -- create moon path package from lua package path create_moonpath = (package_path) -> @@ -82,3 +77,9 @@ dofile = (fname, options) -> f = assert loadfile fname f! +{ + _NAME: "moonscript" + :to_lua, :moon_chunk, :moon_loader, :dirsep, :dofile, :loadfile, + :loadstring +} + diff --git a/moonscript/line_tables.lua b/moonscript/line_tables.lua new file mode 100644 index 00000000..61388ecb --- /dev/null +++ b/moonscript/line_tables.lua @@ -0,0 +1 @@ +return { } diff --git a/moonscript/line_tables.moon b/moonscript/line_tables.moon new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/moonscript/line_tables.moon @@ -0,0 +1 @@ +{} diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 808920eb..f12011cb 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -1,7 +1,7 @@ local util = require"moonscript.util" -require"lpeg" +local lpeg = require"lpeg" local debug_grammar = false @@ -13,6 +13,9 @@ local ntype = types.ntype local dump = util.dump local trim = util.trim +local getfenv = util.getfenv +local setfenv = util.setfenv + local Stack = data.Stack local function count_indent(str) From 4d56430d4f82b122ed0506200176c7700b4ad3e2 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 2 Jan 2013 13:59:49 -0800 Subject: [PATCH 047/554] package.loaders -> package.searchers for 5.2 --- moonscript/init.lua | 4 ++-- moonscript/init.moon | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/moonscript/init.lua b/moonscript/init.lua index 8ea4560c..84587328 100644 --- a/moonscript/init.lua +++ b/moonscript/init.lua @@ -67,9 +67,9 @@ if not package.moonpath then end local init_loader init_loader = function() - return insert(package.loaders, 2, moon_loader) + return insert(package.loaders or package.searchers, 2, moon_loader) end -if not _G.moon_no_loader then +if not (_G.moon_no_loader) then init_loader() end local loadstring diff --git a/moonscript/init.moon b/moonscript/init.moon index 260c88fb..df0578a7 100644 --- a/moonscript/init.moon +++ b/moonscript/init.moon @@ -53,9 +53,9 @@ if not package.moonpath package.moonpath = create_moonpath package.path init_loader = -> - insert package.loaders, 2, moon_loader + insert package.loaders or package.searchers, 2, moon_loader -init_loader! if not _G.moon_no_loader +init_loader! unless _G.moon_no_loader loadstring = (str, chunk_name, options=nil) -> passed, code, ltable = pcall -> to_lua str, options From 3ec2f18b6bc8161c608319dca22f4954a4ee0bc6 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 2 Jan 2013 17:23:29 -0800 Subject: [PATCH 048/554] get options and unpack --- moonscript/util.lua | 17 ++++++++++++++++- moonscript/util.moon | 14 +++++++++++++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/moonscript/util.lua b/moonscript/util.lua index 47ed3908..a2cdbe6c 100644 --- a/moonscript/util.lua +++ b/moonscript/util.lua @@ -1,4 +1,5 @@ local concat = table.concat +local unpack = unpack or table.unpack local moon = { is_object = function(value) return type(value) == "table" and value.__class @@ -173,6 +174,18 @@ local getfenv = getfenv or function(fn) end return nil end +local get_options +get_options = function(...) + local count = select("#", ...) + local opts = select(count, ...) + if type(opts) == "table" then + return opts, unpack({ + ... + }, nil, count - 1) + else + return { }, ... + end +end return { moon = moon, pos_to_line = pos_to_line, @@ -184,5 +197,7 @@ return { dump = dump, debug_posmap = debug_posmap, getfenv = getfenv, - setfenv = setfenv + setfenv = setfenv, + get_options = get_options, + unpack = unpack } diff --git a/moonscript/util.moon b/moonscript/util.moon index 65fcaaeb..93d9797c 100644 --- a/moonscript/util.moon +++ b/moonscript/util.moon @@ -1,6 +1,8 @@ import concat from table +unpack = unpack or table.unpack + moon = is_object: (value) -> -- is a moonscript object type(value) == "table" and value.__class @@ -105,8 +107,18 @@ getfenv = getfenv or (fn) -> i += 1 nil +-- moves the last argument to the front if it's a table, or returns empty table +-- inserted to the front of args +get_options = (...) -> + count = select "#", ... + opts = select count, ... + if type(opts) == "table" + opts, unpack {...}, nil, count - 1 + else + {}, ... + { :moon, :pos_to_line, :get_closest_line, :get_line, :reversed, :trim, :split, - :dump, :debug_posmap, :getfenv, :setfenv + :dump, :debug_posmap, :getfenv, :setfenv, :get_options, :unpack } From cbf624d0f6f5033ad4bdb7a5eff5748cc4712be8 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 2 Jan 2013 17:23:58 -0800 Subject: [PATCH 049/554] update load functions for 5.2 --- moonscript.lua | 2 +- moonscript/init.lua | 27 +++++++++++++-------------- moonscript/init.moon | 18 +++++++++++------- 3 files changed, 25 insertions(+), 22 deletions(-) diff --git a/moonscript.lua b/moonscript.lua index e3a64e5a..dd876be9 100644 --- a/moonscript.lua +++ b/moonscript.lua @@ -1 +1 @@ -require "moonscript.init" +return require "moonscript.init" diff --git a/moonscript/init.lua b/moonscript/init.lua index 84587328..3474a925 100644 --- a/moonscript/init.lua +++ b/moonscript/init.lua @@ -1,10 +1,10 @@ local compile = require("moonscript.compile") local parse = require("moonscript.parse") local concat, insert = table.concat, table.insert -local split, dump +local split, dump, get_options, unpack do local _table_0 = require("moonscript.util") - split, dump = _table_0.split, _table_0.dump + split, dump, get_options, unpack = _table_0.split, _table_0.dump, _table_0.get_options, _table_0.unpack end local lua = { loadstring = loadstring @@ -73,10 +73,9 @@ if not (_G.moon_no_loader) then init_loader() end local loadstring -loadstring = function(str, chunk_name, options) - if options == nil then - options = nil - end +loadstring = function(...) + local options, str, chunk_name, mode, env = get_options(...) + chunk_name = chunk_name or "=(moonscript.loadstring)" local passed, code, ltable = pcall(function() return to_lua(str, options) end) @@ -86,24 +85,24 @@ loadstring = function(str, chunk_name, options) if chunk_name then line_tables[chunk_name] = ltable end - return lua.loadstring(code, chunk_name or "=(moonscript.loadstring)") + return (lua.loadstring or lua.load)(code, chunk_name, unpack({ + mode, + env + })) end local loadfile -loadfile = function(fname, options) - if options == nil then - options = nil - end +loadfile = function(fname, ...) local file, err = io.open(fname) if not file then return nil, err end local text = assert(file:read("*a")) file:close() - return loadstring(text, fname, options) + return loadstring(text, fname, ...) end local dofile -dofile = function(fname, options) - local f = assert(loadfile(fname)) +dofile = function(...) + local f = assert(loadfile(...)) return f() end return { diff --git a/moonscript/init.moon b/moonscript/init.moon index df0578a7..cb97d1db 100644 --- a/moonscript/init.moon +++ b/moonscript/init.moon @@ -3,7 +3,7 @@ compile = require "moonscript.compile" parse = require "moonscript.parse" import concat, insert from table -import split, dump from require "moonscript.util" +import split, dump, get_options, unpack from require "moonscript.util" lua = :loadstring @@ -57,24 +57,28 @@ init_loader = -> init_loader! unless _G.moon_no_loader -loadstring = (str, chunk_name, options=nil) -> +loadstring = (...) -> + options, str, chunk_name, mode, env = get_options ... + chunk_name or= "=(moonscript.loadstring)" + passed, code, ltable = pcall -> to_lua str, options if not passed error chunk_name .. ": " .. code, 2 line_tables[chunk_name] = ltable if chunk_name - lua.loadstring code, chunk_name or "=(moonscript.loadstring)" + -- the unpack prevents us from passing nil + (lua.loadstring or lua.load) code, chunk_name, unpack { mode, env } -loadfile = (fname, options=nil) -> +loadfile = (fname, ...) -> file, err = io.open fname return nil, err if not file text = assert file\read "*a" file\close! - loadstring text, fname, options + loadstring text, fname, ... -- throws errros -dofile = (fname, options) -> - f = assert loadfile fname +dofile = (...) -> + f = assert loadfile ... f! { From 999a9bed20d4bd8f6153f570d0a93577bcc52e81 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 2 Jan 2013 17:32:00 -0800 Subject: [PATCH 050/554] update bin scripts for 5.2 --- bin/moon | 4 ++-- bin/moonc | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/bin/moon b/bin/moon index ae455e98..6d5ed217 100755 --- a/bin/moon +++ b/bin/moon @@ -1,7 +1,7 @@ #!/usr/bin/env lua require "alt_getopt" -require "moonscript" +local moonscript = require "moonscript" local util = require "moonscript.util" local errors = require "moonscript.errors" @@ -66,7 +66,7 @@ if not moonscript_chunk then os.exit(1) end -getfenv(moonscript_chunk).arg = new_arg +util.getfenv(moonscript_chunk).arg = new_arg if not opts.d then local err, trace diff --git a/bin/moonc b/bin/moonc index 15cc49a0..6ec0a1c0 100755 --- a/bin/moonc +++ b/bin/moonc @@ -1,7 +1,5 @@ #!/usr/bin/env lua -module("moonscript", package.seeall) - local parse = require "moonscript.parse" local compile = require "moonscript.compile" local util = require "moonscript.util" @@ -267,7 +265,8 @@ function get_sleep_func() require "socket" sleep = socket.sleep end) then - sleep = moonscript._sleep + -- This is set by moonc.c in windows binaries + sleep = require("moonscript")._sleep end if not sleep then error("Missing sleep function; install LuaSocket") From 35bcdc729bc2e85c381e7cb130a171a43b6e5702 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 2 Jan 2013 17:47:42 -0800 Subject: [PATCH 051/554] use os.clock if lua socket is not available for test2 --- test2.moon | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test2.moon b/test2.moon index 2aee2a5e..1b6a819d 100644 --- a/test2.moon +++ b/test2.moon @@ -32,6 +32,8 @@ pcall -> require "socket" gettime = socket.gettime +gettime or= os.clock + benchmark = (fn) -> if gettime start = gettime! From 0ba4c773e18a5fe0fe708fe63ef75c1229cf42c1 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 2 Jan 2013 17:55:43 -0800 Subject: [PATCH 052/554] don't reference global unpack --- bin/moon | 2 ++ moonscript/compile.lua | 2 +- moonscript/compile.moon | 2 +- moonscript/compile/statement.lua | 4 ++-- moonscript/compile/statement.moon | 2 +- moonscript/compile/value.lua | 1 + moonscript/compile/value.moon | 1 + moonscript/parse.lua | 1 + moonscript/transform.lua | 2 +- moonscript/transform.moon | 2 +- moonscript/transform/destructure.lua | 5 +++++ moonscript/transform/destructure.moon | 1 + moonscript/transform/names.lua | 5 +++++ moonscript/transform/names.moon | 1 + moonscript/types.lua | 1 + moonscript/types.moon | 1 + test2.moon | 2 ++ 17 files changed, 28 insertions(+), 7 deletions(-) diff --git a/bin/moon b/bin/moon index 6d5ed217..5ce9d414 100755 --- a/bin/moon +++ b/bin/moon @@ -6,6 +6,8 @@ local moonscript = require "moonscript" local util = require "moonscript.util" local errors = require "moonscript.errors" +local unpack = util.unpack + -- moonloader and repl local opts, ind = alt_getopt.get_opts(arg, "cvhd", { version = "v", help = "h" }) diff --git a/moonscript/compile.lua b/moonscript/compile.lua index e0128424..7e9c2e81 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -27,7 +27,7 @@ do value_compilers = _table_0.value_compilers end local concat, insert = table.concat, table.insert -local pos_to_line, get_closest_line, trim = util.pos_to_line, util.get_closest_line, util.trim +local pos_to_line, get_closest_line, trim, unpack = util.pos_to_line, util.get_closest_line, util.trim, util.unpack local mtype = util.moon.type local indent_char = " " local Line, Lines, Block, RootBlock diff --git a/moonscript/compile.moon b/moonscript/compile.moon index c289b6aa..a74f74d0 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -11,7 +11,7 @@ import statement_compilers from require "moonscript.compile.statement" import value_compilers from require "moonscript.compile.value" import concat, insert from table -import pos_to_line, get_closest_line, trim from util +import pos_to_line, get_closest_line, trim, unpack from util mtype = util.moon.type diff --git a/moonscript/compile/statement.lua b/moonscript/compile/statement.lua index 4c8ae3eb..2ee23489 100644 --- a/moonscript/compile/statement.lua +++ b/moonscript/compile/statement.lua @@ -1,7 +1,7 @@ -local reversed +local reversed, unpack do local _table_0 = require("moonscript.util") - reversed = _table_0.reversed + reversed, unpack = _table_0.reversed, _table_0.unpack end local ntype do diff --git a/moonscript/compile/statement.moon b/moonscript/compile/statement.moon index d390186a..befc6413 100644 --- a/moonscript/compile/statement.moon +++ b/moonscript/compile/statement.moon @@ -1,5 +1,5 @@ -import reversed from require "moonscript.util" +import reversed, unpack from require "moonscript.util" import ntype from require "moonscript.types" import concat, insert from table diff --git a/moonscript/compile/value.lua b/moonscript/compile/value.lua index 7f9c30bf..98fd3952 100644 --- a/moonscript/compile/value.lua +++ b/moonscript/compile/value.lua @@ -11,6 +11,7 @@ do user_error = _table_0.user_error end local concat, insert = table.concat, table.insert +local unpack = util.unpack local table_delim = "," local value_compilers = { exp = function(self, node) diff --git a/moonscript/compile/value.moon b/moonscript/compile/value.moon index 87e47141..faf4b916 100644 --- a/moonscript/compile/value.moon +++ b/moonscript/compile/value.moon @@ -5,6 +5,7 @@ data = require "moonscript.data" import ntype from require "moonscript.types" import user_error from require "moonscript.errors" import concat, insert from table +import unpack from util table_delim = "," diff --git a/moonscript/parse.lua b/moonscript/parse.lua index f12011cb..2cd5f950 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -15,6 +15,7 @@ local trim = util.trim local getfenv = util.getfenv local setfenv = util.setfenv +local unpack = util.unpack local Stack = data.Stack diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 47444e89..10482c6c 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -1,7 +1,7 @@ local types = require("moonscript.types") local util = require("moonscript.util") local data = require("moonscript.data") -local reversed = util.reversed +local reversed, unpack = util.reversed, util.unpack local ntype, mtype, build, smart_node, is_slice, value_is_singular = types.ntype, types.mtype, types.build, types.smart_node, types.is_slice, types.value_is_singular local insert = table.insert local NameProxy, LocalName diff --git a/moonscript/transform.moon b/moonscript/transform.moon index 067845ee..22c6b668 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -3,7 +3,7 @@ types = require "moonscript.types" util = require "moonscript.util" data = require "moonscript.data" -import reversed from util +import reversed, unpack from util import ntype, mtype, build, smart_node, is_slice, value_is_singular from types import insert from table import NameProxy, LocalName from require "moonscript.transform.names" diff --git a/moonscript/transform/destructure.lua b/moonscript/transform/destructure.lua index ca9fdace..876435b6 100644 --- a/moonscript/transform/destructure.lua +++ b/moonscript/transform/destructure.lua @@ -9,6 +9,11 @@ do NameProxy = _table_0.NameProxy end local insert = table.insert +local unpack +do + local _table_0 = require("moonscript.util") + unpack = _table_0.unpack +end local user_error do local _table_0 = require("moonscript.errors") diff --git a/moonscript/transform/destructure.moon b/moonscript/transform/destructure.moon index 7d73f4d6..4863729c 100644 --- a/moonscript/transform/destructure.moon +++ b/moonscript/transform/destructure.moon @@ -2,6 +2,7 @@ import ntype, mtype, build from require "moonscript.types" import NameProxy from require "moonscript.transform.names" import insert from table +import unpack from require "moonscript.util" import user_error from require "moonscript.errors" diff --git a/moonscript/transform/names.lua b/moonscript/transform/names.lua index 4eb294d6..5e58c093 100644 --- a/moonscript/transform/names.lua +++ b/moonscript/transform/names.lua @@ -3,6 +3,11 @@ do local _table_0 = require("moonscript.types") build = _table_0.build end +local unpack +do + local _table_0 = require("moonscript.util") + unpack = _table_0.unpack +end local LocalName do local _parent_0 = nil diff --git a/moonscript/transform/names.moon b/moonscript/transform/names.moon index 79a2b00d..24fc126b 100644 --- a/moonscript/transform/names.moon +++ b/moonscript/transform/names.moon @@ -1,5 +1,6 @@ import build from require "moonscript.types" +import unpack from require "moonscript.util" -- always declares as local class LocalName diff --git a/moonscript/types.lua b/moonscript/types.lua index b145e208..3b1ad954 100644 --- a/moonscript/types.lua +++ b/moonscript/types.lua @@ -1,6 +1,7 @@ local util = require("moonscript.util") local data = require("moonscript.data") local insert = table.insert +local unpack = util.unpack local manual_return = data.Set({ "foreach", "for", diff --git a/moonscript/types.moon b/moonscript/types.moon index c6df7f41..992ff779 100644 --- a/moonscript/types.moon +++ b/moonscript/types.moon @@ -3,6 +3,7 @@ util = require "moonscript.util" data = require "moonscript.data" import insert from table +import unpack from util -- implicit return does not work on these statements manual_return = data.Set{"foreach", "for", "while", "return"} diff --git a/test2.moon b/test2.moon index 1b6a819d..d2a64088 100644 --- a/test2.moon +++ b/test2.moon @@ -8,6 +8,8 @@ util = require "moonscript.util" pattern = ... +import unpack from util + options = { in_dir: "tests/inputs", out_dir: "tests/outputs", From 59110dd00f9e8f838918a9b22511217699fe75bc Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 2 Jan 2013 17:58:55 -0800 Subject: [PATCH 053/554] update readme --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c7461be8..52fa23f5 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # MoonScript MoonScript is a programmer friendly language that compiles into -[Lua](http://www.lua.org/). It gives you the power of the fastest scripting -language combined with a rich set of features. +[Lua](http://www.lua.org/). It gives you the power of the fastest scripting +language combined with a rich set of features. It runs on Lua 5.1 and 5.2. See . @@ -10,7 +10,7 @@ Online demo/compiler at . ## License (MIT) -Copyright (C) 2011 by Leaf Corcoran +Copyright (C) 2012 by Leaf Corcoran Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 71d9742fafe3a0ff380a48ad121f1b0be509f798 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 9 Jan 2013 19:42:39 -0800 Subject: [PATCH 054/554] update rockspec --- moonscript-dev-1.rockspec | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/moonscript-dev-1.rockspec b/moonscript-dev-1.rockspec index 9e191f13..9906efc8 100644 --- a/moonscript-dev-1.rockspec +++ b/moonscript-dev-1.rockspec @@ -22,22 +22,23 @@ dependencies = { build = { type = "builtin", modules = { - ["moonscript.transform.destructure"] = "moonscript/transform/destructure.lua", - ["moonscript.transform.names"] = "moonscript/transform/names.lua", - ["moonscript.transform"] = "moonscript/transform.lua", - ["moonscript.data"] = "moonscript/data.lua", - ["moonscript.version"] = "moonscript/version.lua", - ["moonscript.types"] = "moonscript/types.lua", + ["moon"] = "moon/init.lua", + ["moon.all"] = "moon/all.lua", + ["moonscript"] = "moonscript/init.lua", ["moonscript.compile"] = "moonscript/compile.lua", - ["moonscript.parse"] = "moonscript/parse.lua", - ["moonscript.util"] = "moonscript/util.lua", - ["moonscript.dump"] = "moonscript/dump.lua", ["moonscript.compile.statement"] = "moonscript/compile/statement.lua", ["moonscript.compile.value"] = "moonscript/compile/value.lua", - ["moonscript"] = "moonscript/init.lua", + ["moonscript.data"] = "moonscript/data.lua", + ["moonscript.dump"] = "moonscript/dump.lua", ["moonscript.errors"] = "moonscript/errors.lua", - ["moon.all"] = "moon/all.lua", - ["moon"] = "moon/init.lua", + ["moonscript.line_tables"] = "moonscript/line_tables.lua", + ["moonscript.parse"] = "moonscript/parse.lua", + ["moonscript.transform"] = "moonscript/transform.lua", + ["moonscript.transform.destructure"] = "moonscript/transform/destructure.lua", + ["moonscript.transform.names"] = "moonscript/transform/names.lua", + ["moonscript.types"] = "moonscript/types.lua", + ["moonscript.util"] = "moonscript/util.lua", + ["moonscript.version"] = "moonscript/version.lua", }, install = { bin = { "bin/moon", "bin/moonc" } From c689acc93589e2a91e802c1aa5127043b581f4cc Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 9 Jan 2013 19:47:02 -0800 Subject: [PATCH 055/554] fix typo in fold (thanks Georg Schmid) --- moon/init.lua | 2 +- moon/init.moon | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/moon/init.lua b/moon/init.lua index af6337a3..5cf4be88 100644 --- a/moon/init.lua +++ b/moon/init.lua @@ -154,7 +154,7 @@ fold = function(items, fn) if len > 1 then local accum = fn(items[1], items[2]) for i = 3, len do - accum = fn(acum, items[i]) + accum = fn(accum, items[i]) end return accum else diff --git a/moon/init.moon b/moon/init.moon index f3d822e9..22cce0c7 100644 --- a/moon/init.moon +++ b/moon/init.moon @@ -129,7 +129,7 @@ fold = (items, fn)-> if len > 1 accum = fn items[1], items[2] for i=3,len - accum = fn acum, items[i] + accum = fn accum, items[i] accum else items[1] From 329d65784ea096d69e3e37d0d38b6c2aa92eeed7 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 10 Jan 2013 17:53:47 -0800 Subject: [PATCH 056/554] fix missing dump function for -T --- bin/moonc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bin/moonc b/bin/moonc index 6ec0a1c0..1601d9ce 100755 --- a/bin/moonc +++ b/bin/moonc @@ -4,6 +4,8 @@ local parse = require "moonscript.parse" local compile = require "moonscript.compile" local util = require "moonscript.util" +local dump_tree = require"moonscript.dump".tree + require "alt_getopt" require "lfs" @@ -117,7 +119,7 @@ function compile_file(text, fname) if opts.T then opts.p = true - dump.tree(tree) + dump_tree(tree) return "" else local compile_time = gettime() From 0306608e3094746ab36533ddde8a9d46adabc453 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 10 Jan 2013 19:56:33 -0800 Subject: [PATCH 057/554] is_a --- moonscript/util.lua | 14 ++++++++++++++ moonscript/util.moon | 12 ++++++++++++ 2 files changed, 26 insertions(+) diff --git a/moonscript/util.lua b/moonscript/util.lua index a2cdbe6c..9924872f 100644 --- a/moonscript/util.lua +++ b/moonscript/util.lua @@ -1,9 +1,23 @@ local concat = table.concat local unpack = unpack or table.unpack +local type = type local moon = { is_object = function(value) return type(value) == "table" and value.__class end, + is_a = function(thing, t) + if not (type(thing) == "table") then + return false + end + local cls = thing.__class + while cls do + if cls == t then + return true + end + cls = cls.__parent + end + return false + end, type = function(value) local base_type = type(value) if base_type == "table" then diff --git a/moonscript/util.moon b/moonscript/util.moon index 93d9797c..d43d0505 100644 --- a/moonscript/util.moon +++ b/moonscript/util.moon @@ -2,10 +2,22 @@ import concat from table unpack = unpack or table.unpack +type = type moon = is_object: (value) -> -- is a moonscript object type(value) == "table" and value.__class + + is_a: (thing, t) -> + return false unless type(thing) == "table" + cls = thing.__class + while cls + if cls == t + return true + cls = cls.__parent + + false + type: (value) -> -- the moonscript object class base_type = type value if base_type == "table" From fa06e6103d8cb9f5c8aba3b3e06051662e76e087 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 10 Jan 2013 20:14:23 -0800 Subject: [PATCH 058/554] delayed line --- moonscript/compile.lua | 60 ++++++++++++++++++++++++++++++++++++----- moonscript/compile.moon | 32 ++++++++++++++++------ moonscript/data.moon | 2 -- 3 files changed, 77 insertions(+), 17 deletions(-) diff --git a/moonscript/compile.lua b/moonscript/compile.lua index 7e9c2e81..7de29aa0 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -30,7 +30,7 @@ local concat, insert = table.concat, table.insert local pos_to_line, get_closest_line, trim, unpack = util.pos_to_line, util.get_closest_line, util.trim, util.unpack local mtype = util.moon.type local indent_char = " " -local Line, Lines, Block, RootBlock +local Line, DelayedLine, Lines, Block, RootBlock do local _parent_0 = nil local _base_0 = { @@ -62,13 +62,13 @@ do end local posmap = self.posmap for i, l in ipairs(self) do - local _exp_0 = type(l) - if "table" == _exp_0 then - local _ - _, line_no = l:flatten_posmap(line_no, out) - elseif "string" == _exp_0 then + local _exp_0 = mtype(l) + if "string" == _exp_0 or DelayedLine == _exp_0 then line_no = line_no + 1 out[line_no] = posmap[i] + elseif "table" == _exp_0 then + local _ + _, line_no = l:flatten_posmap(line_no, out) end end return out, line_no @@ -82,7 +82,12 @@ do end for i = 1, #self do local l = self[i] - local _exp_0 = type(l) + local t = mtype(l) + if t == DelayedLine then + l = l:render() + t = "string" + end + local _exp_0 = t if "string" == _exp_0 then if indent then insert(buffer, indent) @@ -264,6 +269,47 @@ do end Line = _class_0 end +do + local _parent_0 = nil + local _base_0 = { + prepare = function() end, + render = function(self) + self:prepare() + return concat(self) + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, fn) + self.prepare = fn + end, + __base = _base_0, + __name = "DelayedLine", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + DelayedLine = _class_0 +end do local _parent_0 = nil local _base_0 = { diff --git a/moonscript/compile.moon b/moonscript/compile.moon index a74f74d0..9f4b3ebd 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -17,7 +17,7 @@ mtype = util.moon.type indent_char = " " -local Line, Lines, Block, RootBlock +local Line, DelayedLine, Lines, Block, RootBlock -- a buffer for building up lines class Lines @@ -34,26 +34,32 @@ class Lines item\render self when Block item\render self - else + else -- also captures DelayedLine @[#@ + 1] = item @ flatten_posmap: (line_no=0, out={}) => posmap = @posmap for i, l in ipairs @ - switch type l - when "table" - _, line_no = l\flatten_posmap line_no, out - when "string" + switch mtype l + when "string", DelayedLine line_no += 1 out[line_no] = posmap[i] + when "table" + _, line_no = l\flatten_posmap line_no, out out, line_no flatten: (indent=nil, buffer={}) => for i = 1, #@ l = @[i] - switch type l + t = mtype l + + if t == DelayedLine + l = l\render! + t = "string" + + switch t when "string" insert buffer, indent if indent insert buffer, l @@ -66,7 +72,7 @@ class Lines insert buffer, "\n" last = l - when "table" + when "table" -- Lines l\flatten indent and indent .. indent_char or indent_char, buffer buffer @@ -134,6 +140,16 @@ class Line __tostring: => "Line<#{util.dump(@)\sub 1, -2}>" +class DelayedLine + new: (fn) => + @prepare = fn + + prepare: -> + + render: => + @prepare! + concat @ + class Block header: "do" footer: "end" diff --git a/moonscript/data.moon b/moonscript/data.moon index 52df3d51..a9fbf328 100644 --- a/moonscript/data.moon +++ b/moonscript/data.moon @@ -33,7 +33,5 @@ lua_keywords = Set{ 'until', 'while' } - { :Set, :Stack, :lua_keywords } - From 54dc8efa0bd44460c4c9b001afb0031d8f03951b Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 10 Jan 2013 20:20:05 -0800 Subject: [PATCH 059/554] local * --- moonscript/compile.lua | 11 +++++++++++ moonscript/compile.moon | 5 +++++ moonscript/compile/statement.lua | 25 ++++++++++++++++++++----- moonscript/compile/statement.moon | 18 +++++++++++++++++- moonscript/parse.lua | 2 +- moonscript/transform.lua | 12 ++++++++++++ moonscript/transform.moon | 6 ++++++ 7 files changed, 72 insertions(+), 7 deletions(-) diff --git a/moonscript/compile.lua b/moonscript/compile.lua index 7de29aa0..1772c8d1 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -749,6 +749,17 @@ tree = function(tree, options) return lua_code, posmap end end +do + local _with_0 = require("moonscript.data") + local data = _with_0 + for name, cls in pairs({ + Line = Line, + Lines = Lines, + DelayedLine = DelayedLine + }) do + data[name] = cls + end +end return { tree = tree, value = value, diff --git a/moonscript/compile.moon b/moonscript/compile.moon index 9f4b3ebd..91068e90 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -411,4 +411,9 @@ tree = (tree, options={}) -> posmap = scope._lines\flatten_posmap! lua_code, posmap +-- mmmm +with data = require "moonscript.data" + for name, cls in pairs {:Line, :Lines, :DelayedLine} + data[name] = cls + { :tree, :value, :format_error, :Block, :RootBlock } diff --git a/moonscript/compile/statement.lua b/moonscript/compile/statement.lua index 2ee23489..49b4812b 100644 --- a/moonscript/compile/statement.lua +++ b/moonscript/compile/statement.lua @@ -1,8 +1,6 @@ -local reversed, unpack -do - local _table_0 = require("moonscript.util") - reversed, unpack = _table_0.reversed, _table_0.unpack -end +local util = require("moonscript.util") +local data = require("moonscript.data") +local reversed, unpack = util.reversed, util.unpack local ntype do local _table_0 = require("moonscript.types") @@ -41,6 +39,23 @@ local statement_compilers = { end end end, + declare_glob = function(self, node) + local names = { } + self:set("name_glob", function(name) + insert(names, name) + return true + end) + return data.DelayedLine(function(buff) + insert(buff, "local ") + local _list_0 = names + for _index_0 = 1, #_list_0 do + local name = _list_0[_index_0] + insert(buff, self:name(name)) + insert(buff, ", ") + end + buff[#buff] = nil + end) + end, declare_with_shadows = function(self, node) local names = node[2] self:declare(names) diff --git a/moonscript/compile/statement.moon b/moonscript/compile/statement.moon index befc6413..704aaad4 100644 --- a/moonscript/compile/statement.moon +++ b/moonscript/compile/statement.moon @@ -1,5 +1,8 @@ -import reversed, unpack from require "moonscript.util" +util = require "moonscript.util" +data = require "moonscript.data" + +import reversed, unpack from util import ntype from require "moonscript.types" import concat, insert from table @@ -17,6 +20,19 @@ statement_compilers = with @line "local " \append_list [@name name for name in *undeclared], ", " + declare_glob: (node) => + names = {} + @set "name_glob", (name) -> + insert names, name + true + + data.DelayedLine (buff) -> + insert buff, "local " + for name in *names + insert buff, @name name + insert buff, ", " + buff[#buff] = nil -- strips local if no names + -- this overrides the existing names with new locals, used for local keyword declare_with_shadows: (node) => names = node[2] diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 2cd5f950..23ae998d 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -404,7 +404,7 @@ local build_grammar = wrap_env(function() PopIndent = Cmt("", pop_indent), InBlock = Advance * Block * PopIndent, - Local = key"local" * Ct(NameList) / mark"declare_with_shadows", + Local = key"local" * ((op"*" + op"^") / mark"declare_glob" + Ct(NameList) / mark"declare_with_shadows"), Import = key"import" * Ct(ImportNameList) * key"from" * Exp / mark"import", ImportName = (sym"\\" * Ct(Cc"colon_stub" * Name) + Name), diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 10482c6c..8c7cbac7 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -329,6 +329,18 @@ local Statement = Transformer({ end, assign = function(self, node) local names, values = unpack(node, 2) + do + local globber = self:get("name_glob") + if globber then + local _list_0 = names + for _index_0 = 1, #_list_0 do + local name = _list_0[_index_0] + if globber(name) then + self:put_name(name) + end + end + end + end local transformed if #values == 1 then local value = values[1] diff --git a/moonscript/transform.moon b/moonscript/transform.moon index 22c6b668..31bc6de0 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -158,6 +158,12 @@ Statement = Transformer { assign: (node) => names, values = unpack node, 2 + + if globber = @get "name_glob" + for name in *names + if globber name + @put_name name + -- bubble cascading assigns transformed = if #values == 1 value = values[1] From 19032214a8a9c7f0e86e225755afd0bab5dc4d3b Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 11 Jan 2013 10:06:03 -0800 Subject: [PATCH 060/554] correctly check types, issue from DelayedLine --- moonscript/compile.lua | 8 ++++++-- moonscript/compile.moon | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/moonscript/compile.lua b/moonscript/compile.lua index 1772c8d1..57fd30b3 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -66,9 +66,11 @@ do if "string" == _exp_0 or DelayedLine == _exp_0 then line_no = line_no + 1 out[line_no] = posmap[i] - elseif "table" == _exp_0 then + elseif Lines == _exp_0 then local _ _, line_no = l:flatten_posmap(line_no, out) + else + error("Unknown item in Lines: " .. tostring(l)) end end return out, line_no @@ -101,8 +103,10 @@ do end insert(buffer, "\n") local last = l - elseif "table" == _exp_0 then + elseif Lines == _exp_0 then l:flatten(indent and indent .. indent_char or indent_char, buffer) + else + error("Unknown item in Lines: " .. tostring(l)) end end return buffer diff --git a/moonscript/compile.moon b/moonscript/compile.moon index 91068e90..c6249c87 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -45,8 +45,10 @@ class Lines when "string", DelayedLine line_no += 1 out[line_no] = posmap[i] - when "table" + when Lines _, line_no = l\flatten_posmap line_no, out + else + error "Unknown item in Lines: #{l}" out, line_no @@ -72,8 +74,10 @@ class Lines insert buffer, "\n" last = l - when "table" -- Lines + when Lines l\flatten indent and indent .. indent_char or indent_char, buffer + else + error "Unknown item in Lines: #{l}" buffer __tostring: => From 0759cd640e36be5f4fffd1d01d16708f7ef04e9b Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 12 Jan 2013 10:33:12 -0800 Subject: [PATCH 061/554] local glob tests and local ^ --- moonscript/compile.lua | 2 +- moonscript/compile.moon | 2 +- moonscript/compile/statement.lua | 25 +++++++++++++++++++++---- moonscript/compile/statement.moon | 20 +++++++++++++++++--- tests/inputs/local.moon | 24 ++++++++++++++++++++++++ tests/outputs/local.lua | 25 +++++++++++++++++++++++++ 6 files changed, 89 insertions(+), 9 deletions(-) diff --git a/moonscript/compile.lua b/moonscript/compile.lua index 57fd30b3..36a4c101 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -404,7 +404,7 @@ do if self.export_all then return true end - if self.export_proper and name:match("^[A-Z]") then + if self.export_proper and name:match("^%u") then return true end end diff --git a/moonscript/compile.moon b/moonscript/compile.moon index c6249c87..3eab6355 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -234,7 +234,7 @@ class Block has_name: (name, skip_exports) => if not skip_exports return true if @export_all - return true if @export_proper and name\match"^[A-Z]" + return true if @export_proper and name\match"^%u" yes = @_names[name] if yes == nil and @parent diff --git a/moonscript/compile/statement.lua b/moonscript/compile/statement.lua index 49b4812b..77c17d10 100644 --- a/moonscript/compile/statement.lua +++ b/moonscript/compile/statement.lua @@ -40,11 +40,28 @@ local statement_compilers = { end end, declare_glob = function(self, node) + local kind = node[2] local names = { } - self:set("name_glob", function(name) - insert(names, name) - return true - end) + local fn + local _exp_0 = node[2] + if "*" == _exp_0 then + fn = function(name) + if type(name) == "string" then + insert(names, name) + return true + end + end + elseif "^" == _exp_0 then + fn = function(name) + if type(name) == "string" and name:match("^%u") then + insert(names, name) + return true + end + end + else + fn = error("unknown glob") + end + self:set("name_glob", fn) return data.DelayedLine(function(buff) insert(buff, "local ") local _list_0 = names diff --git a/moonscript/compile/statement.moon b/moonscript/compile/statement.moon index 704aaad4..72ce9ae1 100644 --- a/moonscript/compile/statement.moon +++ b/moonscript/compile/statement.moon @@ -21,10 +21,24 @@ statement_compilers = \append_list [@name name for name in *undeclared], ", " declare_glob: (node) => + kind = node[2] + names = {} - @set "name_glob", (name) -> - insert names, name - true + fn = switch node[2] + when "*" + (name) -> + if type(name) == "string" + insert names, name + true + when "^" + (name) -> + if type(name) == "string" and name\match "^%u" + insert names, name + true + else + error "unknown glob" + + @set "name_glob", fn data.DelayedLine (buff) -> insert buff, "local " diff --git a/tests/inputs/local.moon b/tests/inputs/local.moon index 8f30e865..ba1a8001 100644 --- a/tests/inputs/local.moon +++ b/tests/inputs/local.moon @@ -9,3 +9,27 @@ something = -> x = 1212 +do + local * + y = 2323 + z = 2323 + +do + local * + print "Nothing Here!" + +do + local ^ + x = 3434 + y = 3434 + X = 3434 + Y = "yeah" + +do + local ^ + x,y = "a", "b" + +do + local * + x,y = "a", "b" + diff --git a/tests/outputs/local.lua b/tests/outputs/local.lua index b76663ce..830b7b03 100644 --- a/tests/outputs/local.lua +++ b/tests/outputs/local.lua @@ -5,4 +5,29 @@ local something something = function() local x x = 1212 +end +do + local y, z + y = 2323 + z = 2323 +end +do + + print("Nothing Here!") +end +do + local X, Y + x = 3434 + local y = 3434 + X = 3434 + Y = "yeah" +end +do + + local y + x, y = "a", "b" +end +do + local x, y + x, y = "a", "b" end \ No newline at end of file From d4ed7c91ea59b76c8cab4a3c92a0501e88e42065 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 12 Jan 2013 11:04:26 -0800 Subject: [PATCH 062/554] docs for local, fixes #64 --- docs/reference.md | 72 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 68 insertions(+), 4 deletions(-) diff --git a/docs/reference.md b/docs/reference.md index cc6b8712..53107818 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -31,10 +31,10 @@ variable. You can assign multiple names and values at once just like Lua: ``` If you wish to create a global variable it must be done using the -[`export`](#export) keyword. +[`export`](#export_statement) keyword. -The `local` keyword can be used to forward declare a variable, or shadow an -existing one. +The [`local`](#local_statement) keyword can be used to forward declare a +variable, or shadow an existing one. ## Update Assignment @@ -163,7 +163,7 @@ automatically includes a `self` argument. ### Argument Defaults It is possible to provide default values for the arguments of a function. An -argument is determined to be empty if it's value is `nil`. Any `nil` arguments +argument is determined to be empty if its value is `nil`. Any `nil` arguments that have a default value will be replace before the body of the function is run. ```moon @@ -1104,6 +1104,70 @@ The `export` statement can also take special symbols `*` and `^`. current scope. `export ^` will export all proper names, names that begin with a capital letter. +## Local Statement + +Sometimes you want to declare a variable name before the first time you assign +it. The `local` statement can be used to do that. + +In this example we declare the variable `a` in the outer scope so its value +can be accessed after the `if` statement. If there was no `local` statement then +`a` would only be accessible inside the `if` statement. + + ```moon + local a + if something + a = 1 + print a + ``` + +`local` can also be used to shadow existing variables for the rest of a scope. + + ```moon + x = 10 + if something + local x + x = 12 + print x -- prints 10 + ``` + +When you have one function that calls another, you typically order them such +that the second function can access the first. If both functions happen to +call each other, then you must forward declare the names: + + ```moon + local first, second + + first = -> + second! + + second = -> + first! + ``` + +The same problem occurs with declaring classes and regular values too. + +Because forward declaring is often better than manually ordering your assigns, +a special form of `local` is provided: + + ```moon + local * + + first = -> + print data + second! + + second = -> + first! + + data = {} + ``` + +`local *` will forward declare all names below it in the current scope. + +Similarly to [`export`](#export_all_and_export_proper) one more special form is +provided, `local ^`. This will forward declare all names that begin with a +capital letter. + ## Import Statement Often you want to bring some values from a table into the current scope as From 7cd0fcc6321025df6dd60ceed2339806baafdd52 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 12 Jan 2013 13:01:34 -0800 Subject: [PATCH 063/554] update accumulator after expression --- moonscript/transform.lua | 6 ++--- moonscript/transform.moon | 4 +-- tests/outputs/bubbling.lua | 36 ++++++++++++------------- tests/outputs/comprehension.lua | 4 +-- tests/outputs/lists.lua | 48 ++++++++++++++++----------------- tests/outputs/loops.lua | 32 +++++++++++----------- tests/outputs/syntax.lua | 4 +-- 7 files changed, 67 insertions(+), 67 deletions(-) diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 8c7cbac7..d1b0ddb3 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -1238,7 +1238,7 @@ do wrap = function(self, node) return build.block_exp({ build.assign_one(self.accum_name, build.table()), - build.assign_one(self.len_name, 0), + build.assign_one(self.len_name, 1), node, self.accum_name }) @@ -1273,13 +1273,13 @@ do val = self.value_name end local update = { + build.assign_one(self.accum_name:index(self.len_name), val), { "update", self.len_name, "+=", 1 - }, - build.assign_one(self.accum_name:index(self.len_name), val) + } } if skip_nil then table.insert(body, build["if"]({ diff --git a/moonscript/transform.moon b/moonscript/transform.moon index 31bc6de0..57057442 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -691,7 +691,7 @@ class Accumulator wrap: (node) => build.block_exp { build.assign_one @accum_name, build.table! - build.assign_one @len_name, 0 + build.assign_one @len_name, 1 node @accum_name } @@ -715,8 +715,8 @@ class Accumulator @value_name update = { - {"update", @len_name, "+=", 1} build.assign_one @accum_name\index(@len_name), val + {"update", @len_name, "+=", 1} } if skip_nil diff --git a/tests/outputs/bubbling.lua b/tests/outputs/bubbling.lua index d657beaa..f054c1c2 100644 --- a/tests/outputs/bubbling.lua +++ b/tests/outputs/bubbling.lua @@ -8,38 +8,38 @@ local dont_bubble dont_bubble = function() return (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 for x in (function(...) return print(...) end)("hello") do - _len_0 = _len_0 + 1 _accum_0[_len_0] = x + _len_0 = _len_0 + 1 end return _accum_0 end)() end local k = (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 for x in (function(...) return print(...) end)("hello") do - _len_0 = _len_0 + 1 _accum_0[_len_0] = x + _len_0 = _len_0 + 1 end return _accum_0 end)() local j = (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 for i = 1, 10 do local _value_0 _value_0 = function(...) return print(...) end if _value_0 ~= nil then - _len_0 = _len_0 + 1 _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 end end return _accum_0 @@ -48,15 +48,15 @@ local m m = function(...) return (function(...) local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 local _list_0 = { ... } for _index_0 = 1, #_list_0 do local x = _list_0[_index_0] if f(...) > 4 then - _len_0 = _len_0 + 1 _accum_0[_len_0] = x + _len_0 = _len_0 + 1 end end return _accum_0 @@ -64,7 +64,7 @@ m = function(...) end local x = (function(...) local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 local _list_0 = { ... } @@ -72,59 +72,59 @@ local x = (function(...) local i = _list_0[_index_0] local _value_0 = i if _value_0 ~= nil then - _len_0 = _len_0 + 1 _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 end end return _accum_0 end)(...) local y = (function(...) local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 local _list_0 = { ... } for _index_0 = 1, #_list_0 do x = _list_0[_index_0] - _len_0 = _len_0 + 1 _accum_0[_len_0] = x + _len_0 = _len_0 + 1 end return _accum_0 end)(...) local z = (function(...) local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 for x in hallo do if f(...) > 4 then - _len_0 = _len_0 + 1 _accum_0[_len_0] = x + _len_0 = _len_0 + 1 end end return _accum_0 end)(...) local a = (function(...) local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 for i = 1, 10 do local _value_0 = ... if _value_0 ~= nil then - _len_0 = _len_0 + 1 _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 end end return _accum_0 end)(...) local b = (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 for i = 1, 10 do local _value_0 _value_0 = function() return print(...) end if _value_0 ~= nil then - _len_0 = _len_0 + 1 _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 end end return _accum_0 diff --git a/tests/outputs/comprehension.lua b/tests/outputs/comprehension.lua index b0ec9108..0598efe3 100644 --- a/tests/outputs/comprehension.lua +++ b/tests/outputs/comprehension.lua @@ -68,10 +68,10 @@ return (function() x = _list_0[_index_0] local _key_0, _val_0 = unpack((function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 for i, a in ipairs(x) do - _len_0 = _len_0 + 1 _accum_0[_len_0] = a * i + _len_0 = _len_0 + 1 end return _accum_0 end)()) diff --git a/tests/outputs/lists.lua b/tests/outputs/lists.lua index 87936ca8..b6f1b299 100644 --- a/tests/outputs/lists.lua +++ b/tests/outputs/lists.lua @@ -1,14 +1,14 @@ local hi = (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 for _, x in ipairs({ 1, 2, 3, 4 }) do - _len_0 = _len_0 + 1 _accum_0[_len_0] = x * 2 + _len_0 = _len_0 + 1 end return _accum_0 end)() @@ -22,10 +22,10 @@ local items = { } local mm = (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 for self.x in ipairs(items) do - _len_0 = _len_0 + 1 _accum_0[_len_0] = self.x + _len_0 = _len_0 + 1 end return _accum_0 end)() @@ -36,7 +36,7 @@ for z in ipairs(items) do end local rad = (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 for a in ipairs({ 1, 2, @@ -46,10 +46,10 @@ local rad = (function() 6 }) do if good_number(a) then - _len_0 = _len_0 + 1 _accum_0[_len_0] = { a } + _len_0 = _len_0 + 1 end end return _accum_0 @@ -78,24 +78,24 @@ range = function(count) end dump((function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 for x in range(10) do - _len_0 = _len_0 + 1 _accum_0[_len_0] = x + _len_0 = _len_0 + 1 end return _accum_0 end)()) dump((function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 for x in range(5) do if x > 2 then for y in range(5) do - _len_0 = _len_0 + 1 _accum_0[_len_0] = { x, y } + _len_0 = _len_0 + 1 end end end @@ -103,13 +103,13 @@ dump((function() end)()) local things = (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 for x in range(10) do if x > 5 then for y in range(10) do if y > 7 then - _len_0 = _len_0 + 1 _accum_0[_len_0] = x + y + _len_0 = _len_0 + 1 end end end @@ -139,10 +139,10 @@ for x in x do end local x = (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 for x in x do - _len_0 = _len_0 + 1 _accum_0[_len_0] = x + _len_0 = _len_0 + 1 end return _accum_0 end)() @@ -163,12 +163,12 @@ for x in ipairs({ end local double = (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 local _list_0 = items for _index_0 = 1, #_list_0 do x = _list_0[_index_0] - _len_0 = _len_0 + 1 _accum_0[_len_0] = x * 2 + _len_0 = _len_0 + 1 end return _accum_0 end)() @@ -179,28 +179,28 @@ for _index_0 = 1, #_list_0 do end local cut = (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 local _list_1 = items for _index_0 = 1, #_list_1 do x = _list_1[_index_0] if x > 3 then - _len_0 = _len_0 + 1 _accum_0[_len_0] = x + _len_0 = _len_0 + 1 end end return _accum_0 end)() local hello = (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 local _list_1 = items for _index_0 = 1, #_list_1 do x = _list_1[_index_0] local _list_2 = items for _index_1 = 1, #_list_2 do local y = _list_2[_index_1] - _len_0 = _len_0 + 1 _accum_0[_len_0] = x + y + _len_0 = _len_0 + 1 end end return _accum_0 @@ -257,10 +257,10 @@ local normal normal = function(hello) return (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 for x in yeah do - _len_0 = _len_0 + 1 _accum_0[_len_0] = x + _len_0 = _len_0 + 1 end return _accum_0 end)() @@ -289,12 +289,12 @@ end return function() return (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 local _list_9 = things for _index_0 = 1, #_list_9 do x = _list_9[_index_0] - _len_0 = _len_0 + 1 _accum_0[_len_0] = x + _len_0 = _len_0 + 1 end return _accum_0 end)() diff --git a/tests/outputs/loops.lua b/tests/outputs/loops.lua index f538eafd..37c5fb63 100644 --- a/tests/outputs/loops.lua +++ b/tests/outputs/loops.lua @@ -50,7 +50,7 @@ local hello = { } x = (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 local _list_1 = hello for _index_0 = 1, #_list_1 do local y = _list_1[_index_0] @@ -59,8 +59,8 @@ x = (function() _value_0 = y end if _value_0 ~= nil then - _len_0 = _len_0 + 1 _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 end end return _accum_0 @@ -74,12 +74,12 @@ x = function() end local t = (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 for i = 10, 20 do local _value_0 = i * 2 if _value_0 ~= nil then - _len_0 = _len_0 + 1 _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 end end return _accum_0 @@ -87,13 +87,13 @@ end)() local hmm = 0 local y = (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 for j = 3, 30, 8 do hmm = hmm + 1 local _value_0 = j * hmm if _value_0 ~= nil then - _len_0 = _len_0 + 1 _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 end end return _accum_0 @@ -107,12 +107,12 @@ end _ = function() return (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 for k = 10, 40 do local _value_0 = "okay" if _value_0 ~= nil then - _len_0 = _len_0 + 1 _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 end end return _accum_0 @@ -132,41 +132,41 @@ end local i = 0 x = (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 while i < 10 do local _value_0 i = i + 1 if _value_0 ~= nil then - _len_0 = _len_0 + 1 _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 end end return _accum_0 end)() x = (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 local _list_1 = 3 for _index_0 = 1, #_list_1 do local thing = _list_1[_index_0] local _value_0 y = "hello" if _value_0 ~= nil then - _len_0 = _len_0 + 1 _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 end end return _accum_0 end)() x = (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 for x = 1, 2 do local _value_0 y = "hello" if _value_0 ~= nil then - _len_0 = _len_0 + 1 _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 end end return _accum_0 @@ -205,7 +205,7 @@ for x = 1, 10 do end local list = (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 for x = 1, 10 do local _continue_0 = false repeat @@ -215,8 +215,8 @@ local list = (function() end local _value_0 = x if _value_0 ~= nil then - _len_0 = _len_0 + 1 _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 end _continue_0 = true until true diff --git a/tests/outputs/syntax.lua b/tests/outputs/syntax.lua index c78b4635..75b5bc1f 100644 --- a/tests/outputs/syntax.lua +++ b/tests/outputs/syntax.lua @@ -91,10 +91,10 @@ x = -hello(world(one(two))) local hi = -"herfef" x = -(function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 for x in x do - _len_0 = _len_0 + 1 _accum_0[_len_0] = x + _len_0 = _len_0 + 1 end return _accum_0 end)() From 673e0cf61a20618d5edd2e42b50ed822ee11d5cb Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 12 Jan 2013 13:02:27 -0800 Subject: [PATCH 064/554] rebuild --- moonscript/compile.lua | 12 +++++----- moonscript/compile/statement.lua | 24 +++++++++---------- moonscript/compile/value.lua | 20 ++++++++-------- moonscript/dump.lua | 4 ++-- moonscript/errors.lua | 4 ++-- moonscript/transform.lua | 36 ++++++++++++++-------------- moonscript/transform/destructure.lua | 16 ++++++------- moonscript/transform/names.lua | 4 ++-- moonscript/util.lua | 16 ++++++------- 9 files changed, 68 insertions(+), 68 deletions(-) diff --git a/moonscript/compile.lua b/moonscript/compile.lua index 36a4c101..ed6b79a3 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -117,12 +117,12 @@ do if "table" == type(t) then return (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 local _list_0 = t for _index_0 = 1, #_list_0 do local v = _list_0[_index_0] - _len_0 = _len_0 + 1 _accum_0[_len_0] = strip(v) + _len_0 = _len_0 + 1 end return _accum_0 end)() @@ -353,7 +353,7 @@ do declare = function(self, names) local undeclared = (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 local _list_0 = names for _index_0 = 1, #_list_0 do local name = _list_0[_index_0] @@ -373,8 +373,8 @@ do _value_0 = real_name end if _value_0 ~= nil then - _len_0 = _len_0 + 1 _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 end end return _accum_0 @@ -520,12 +520,12 @@ do local _with_0 = Line() _with_0:append_list((function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 local _list_0 = values for _index_0 = 1, #_list_0 do local v = _list_0[_index_0] - _len_0 = _len_0 + 1 _accum_0[_len_0] = self:value(v) + _len_0 = _len_0 + 1 end return _accum_0 end)(), delim) diff --git a/moonscript/compile/statement.lua b/moonscript/compile/statement.lua index 77c17d10..9cfb2ce7 100644 --- a/moonscript/compile/statement.lua +++ b/moonscript/compile/statement.lua @@ -26,12 +26,12 @@ local statement_compilers = { local _with_0 = self:line("local ") _with_0:append_list((function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 local _list_0 = undeclared for _index_0 = 1, #_list_0 do local name = _list_0[_index_0] - _len_0 = _len_0 + 1 _accum_0[_len_0] = self:name(name) + _len_0 = _len_0 + 1 end return _accum_0 end)(), ", ") @@ -80,12 +80,12 @@ local statement_compilers = { local _with_0 = self:line("local ") _with_0:append_list((function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 local _list_0 = names for _index_0 = 1, #_list_0 do local name = _list_0[_index_0] - _len_0 = _len_0 + 1 _accum_0[_len_0] = self:name(name) + _len_0 = _len_0 + 1 end return _accum_0 end)(), ", ") @@ -114,12 +114,12 @@ local statement_compilers = { end _with_0:append_list((function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 local _list_0 = names for _index_0 = 1, #_list_0 do local name = _list_0[_index_0] - _len_0 = _len_0 + 1 _accum_0[_len_0] = self:value(name) + _len_0 = _len_0 + 1 end return _accum_0 end)(), ", ") @@ -127,12 +127,12 @@ local statement_compilers = { _with_0:append(" = ") _with_0:append_list((function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 local _list_0 = values for _index_0 = 1, #_list_0 do local v = _list_0[_index_0] - _len_0 = _len_0 + 1 _accum_0[_len_0] = self:value(v) + _len_0 = _len_0 + 1 end return _accum_0 end)(), ", ") @@ -223,24 +223,24 @@ local statement_compilers = { local _with_0 = self:block(loop) loop:append_list((function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 local _list_0 = names for _index_0 = 1, #_list_0 do local name = _list_0[_index_0] - _len_0 = _len_0 + 1 _accum_0[_len_0] = _with_0:name(name, false) + _len_0 = _len_0 + 1 end return _accum_0 end)(), ", ") loop:append(" in ") loop:append_list((function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 local _list_0 = exps for _index_0 = 1, #_list_0 do local exp = _list_0[_index_0] - _len_0 = _len_0 + 1 _accum_0[_len_0] = self:value(exp) + _len_0 = _len_0 + 1 end return _accum_0 end)(), ",") diff --git a/moonscript/compile/value.lua b/moonscript/compile/value.lua index 98fd3952..f0a69283 100644 --- a/moonscript/compile/value.lua +++ b/moonscript/compile/value.lua @@ -26,11 +26,11 @@ local value_compilers = { local _with_0 = self:line() _with_0:append_list((function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 for i, v in ipairs(node) do if i > 1 then - _len_0 = _len_0 + 1 _accum_0[_len_0] = _comp(i, v) + _len_0 = _len_0 + 1 end end return _accum_0 @@ -43,12 +43,12 @@ local value_compilers = { local _with_0 = self:line() _with_0:append_list((function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 local _list_0 = node for _index_0 = 2, #_list_0 do local v = _list_0[_index_0] - _len_0 = _len_0 + 1 _accum_0[_len_0] = self:value(v) + _len_0 = _len_0 + 1 end return _accum_0 end)(), ", ") @@ -118,7 +118,7 @@ local value_compilers = { local self_args = { } local arg_names = (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 local _list_0 = args for _index_0 = 1, #_list_0 do local arg = _list_0[_index_0] @@ -136,8 +136,8 @@ local value_compilers = { end local _value_0 = name if _value_0 ~= nil then - _len_0 = _len_0 + 1 _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 end end return _accum_0 @@ -185,12 +185,12 @@ local value_compilers = { end local self_arg_values = (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 local _list_2 = self_args for _index_0 = 1, #_list_2 do local arg = _list_2[_index_0] - _len_0 = _len_0 + 1 _accum_0[_len_0] = arg[2] + _len_0 = _len_0 + 1 end return _accum_0 end)() @@ -205,14 +205,14 @@ local value_compilers = { if #args > #arg_names then arg_names = (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 local _list_2 = args for _index_0 = 1, #_list_2 do local arg = _list_2[_index_0] local _value_0 = arg[1] if _value_0 ~= nil then - _len_0 = _len_0 + 1 _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 end end return _accum_0 diff --git a/moonscript/dump.lua b/moonscript/dump.lua index 5e46ed41..edfe4004 100644 --- a/moonscript/dump.lua +++ b/moonscript/dump.lua @@ -11,12 +11,12 @@ flat_value = function(op, depth) end local items = (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 local _list_0 = op for _index_0 = 1, #_list_0 do local item = _list_0[_index_0] - _len_0 = _len_0 + 1 _accum_0[_len_0] = flat_value(item, depth + 1) + _len_0 = _len_0 + 1 end return _accum_0 end)() diff --git a/moonscript/errors.lua b/moonscript/errors.lua index d163d729..85266cf6 100644 --- a/moonscript/errors.lua +++ b/moonscript/errors.lua @@ -44,13 +44,13 @@ truncate_traceback = function(traceback, chunk_func) end traceback = (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 local _list_0 = traceback local _max_0 = stop for _index_0 = 1, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do local t = _list_0[_index_0] - _len_0 = _len_0 + 1 _accum_0[_len_0] = t + _len_0 = _len_0 + 1 end return _accum_0 end)() diff --git a/moonscript/transform.lua b/moonscript/transform.lua index d1b0ddb3..20425f35 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -64,7 +64,7 @@ apply_to_last = function(stms, fn) end return (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 for i, stm in ipairs(stms) do local _value_0 if i == last_exp_id then @@ -73,8 +73,8 @@ apply_to_last = function(stms, fn) _value_0 = stm end if _value_0 ~= nil then - _len_0 = _len_0 + 1 _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 end end return _accum_0 @@ -440,7 +440,7 @@ local Statement = Transformer({ local _, names, source = unpack(node) local stubs = (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 local _list_0 = names for _index_0 = 1, #_list_0 do local name = _list_0[_index_0] @@ -454,22 +454,22 @@ local Statement = Transformer({ } end if _value_0 ~= nil then - _len_0 = _len_0 + 1 _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 end end return _accum_0 end)() local real_names = (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 local _list_0 = names for _index_0 = 1, #_list_0 do local name = _list_0[_index_0] local _value_0 = type(name) == "table" and name[2] or name if _value_0 ~= nil then - _len_0 = _len_0 + 1 _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 end end return _accum_0 @@ -479,15 +479,15 @@ local Statement = Transformer({ names = real_names, values = (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 local _list_0 = stubs for _index_0 = 1, #_list_0 do local stub = _list_0[_index_0] - _len_0 = _len_0 + 1 _accum_0[_len_0] = build.chain({ base = source, stub }) + _len_0 = _len_0 + 1 end return _accum_0 end)() @@ -505,15 +505,15 @@ local Statement = Transformer({ names = real_names, values = (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 local _list_0 = stubs for _index_0 = 1, #_list_0 do local stub = _list_0[_index_0] - _len_0 = _len_0 + 1 _accum_0[_len_0] = build.chain({ base = source_name, stub }) + _len_0 = _len_0 + 1 end return _accum_0 end)() @@ -581,13 +581,13 @@ local Statement = Transformer({ build.declare({ names = (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 local _list_0 = stm[2] for _index_0 = 1, #_list_0 do local name = _list_0[_index_0] if type(name) == "string" then - _len_0 = _len_0 + 1 _accum_0[_len_0] = name + _len_0 = _len_0 + 1 end end return _accum_0 @@ -690,7 +690,7 @@ local Statement = Transformer({ local destructures = { } node.names = (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 for i, name in ipairs(node.names) do local _value_0 if ntype(name) == "table" then @@ -704,8 +704,8 @@ local Statement = Transformer({ _value_0 = name end if _value_0 ~= nil then - _len_0 = _len_0 + 1 _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 end end return _accum_0 @@ -872,7 +872,7 @@ local Statement = Transformer({ local constructor = nil properties = (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 local _list_1 = properties for _index_0 = 1, #_list_1 do local tuple = _list_1[_index_0] @@ -885,8 +885,8 @@ local Statement = Transformer({ _value_0 = tuple end if _value_0 ~= nil then - _len_0 = _len_0 + 1 _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 end end return _accum_0 @@ -1072,12 +1072,12 @@ local Statement = Transformer({ if chain then local slice = (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 local _list_1 = chain for _index_0 = 3, #_list_1 do local item = _list_1[_index_0] - _len_0 = _len_0 + 1 _accum_0[_len_0] = item + _len_0 = _len_0 + 1 end return _accum_0 end)() diff --git a/moonscript/transform/destructure.lua b/moonscript/transform/destructure.lua index 876435b6..6adb7293 100644 --- a/moonscript/transform/destructure.lua +++ b/moonscript/transform/destructure.lua @@ -164,24 +164,24 @@ split_assign = function(assign) "assign", (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 for i = start, stop do local _value_0 = names[i] if _value_0 ~= nil then - _len_0 = _len_0 + 1 _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 end end return _accum_0 end)(), (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 for i = start, stop do local _value_0 = values[i] if _value_0 ~= nil then - _len_0 = _len_0 + 1 _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 end end return _accum_0 @@ -201,12 +201,12 @@ split_assign = function(assign) else name_slice = (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 for i = start, total_names do local _value_0 = names[i] if _value_0 ~= nil then - _len_0 = _len_0 + 1 _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 end end return _accum_0 @@ -220,12 +220,12 @@ split_assign = function(assign) else value_slice = (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 for i = start, total_values do local _value_0 = values[i] if _value_0 ~= nil then - _len_0 = _len_0 + 1 _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 end end return _accum_0 diff --git a/moonscript/transform/names.lua b/moonscript/transform/names.lua index 5e58c093..03faae34 100644 --- a/moonscript/transform/names.lua +++ b/moonscript/transform/names.lua @@ -65,7 +65,7 @@ do chain = function(self, ...) local items = (function(...) local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 local _list_0 = { ... } @@ -81,8 +81,8 @@ do _value_0 = i end if _value_0 ~= nil then - _len_0 = _len_0 + 1 _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 end end return _accum_0 diff --git a/moonscript/util.lua b/moonscript/util.lua index 9924872f..e8058451 100644 --- a/moonscript/util.lua +++ b/moonscript/util.lua @@ -75,10 +75,10 @@ split = function(str, delim) str = str .. delim return (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 for m in str:gmatch("(.-)" .. delim) do - _len_0 = _len_0 + 1 _accum_0[_len_0] = m + _len_0 = _len_0 + 1 end return _accum_0 end)() @@ -102,12 +102,12 @@ dump = function(what) depth = depth + 1 local lines = (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 for k, v in pairs(what) do local _value_0 = (" "):rep(depth * 4) .. "[" .. tostring(k) .. "] = " .. _dump(v, depth) if _value_0 ~= nil then - _len_0 = _len_0 + 1 _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 end end return _accum_0 @@ -124,13 +124,13 @@ local debug_posmap debug_posmap = function(posmap, moon_code, lua_code) local tuples = (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 for k, v in pairs(posmap) do - _len_0 = _len_0 + 1 _accum_0[_len_0] = { k, v } + _len_0 = _len_0 + 1 end return _accum_0 end)() @@ -139,7 +139,7 @@ debug_posmap = function(posmap, moon_code, lua_code) end) local lines = (function() local _accum_0 = { } - local _len_0 = 0 + local _len_0 = 1 local _list_0 = tuples for _index_0 = 1, #_list_0 do local pair = _list_0[_index_0] @@ -149,8 +149,8 @@ debug_posmap = function(posmap, moon_code, lua_code) local moon_text = get_closest_line(moon_code, moon_line) local _value_0 = tostring(pos) .. "\t " .. tostring(lua_line) .. ":[ " .. tostring(trim(lua_text)) .. " ] >> " .. tostring(moon_line) .. ":[ " .. tostring(trim(moon_text)) .. " ]" if _value_0 ~= nil then - _len_0 = _len_0 + 1 _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 end end return _accum_0 From d2444409fef6362f5ef80cdd5fc8312ca17b4fcc Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 12 Jan 2013 13:29:38 -0800 Subject: [PATCH 065/554] remove filtering of nil values from loop expressions (use continue instead) #66 --- moonscript/transform.lua | 33 ++++++------------------ moonscript/transform.moon | 24 +++++++----------- test2.moon | 3 ++- tests/outputs/bubbling.lua | 30 ++++++---------------- tests/outputs/loops.lua | 52 ++++++++++++-------------------------- 5 files changed, 43 insertions(+), 99 deletions(-) diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 20425f35..28684983 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -88,7 +88,7 @@ is_singular = function(body) if "group" == ntype(body) then return is_singular(body[2]) else - return true + return body[1] end end local find_assigns @@ -1243,17 +1243,12 @@ do self.accum_name }) end, - mutate_body = function(self, body, skip_nil) - if skip_nil == nil then - skip_nil = true - end + mutate_body = function(self, body) + local single_stm = is_singular(body) local val - if not skip_nil and is_singular(body) then - do - local _with_0 = body[1] - body = { } - val = _with_0 - end + if single_stm and types.is_value(single_stm) then + body = { } + val = single_stm else body = apply_to_last(body, function(n) if types.is_value(n) then @@ -1281,19 +1276,7 @@ do 1 } } - if skip_nil then - table.insert(body, build["if"]({ - cond = { - "exp", - self.value_name, - "!=", - "nil" - }, - ["then"] = update - })) - else - table.insert(body, build.group(update)) - end + insert(body, build.group(update)) return body end } @@ -1427,7 +1410,7 @@ local Value = Transformer({ node = self.transform.statement(node, function(exp) return a:mutate_body({ exp - }, false) + }) end) return a:wrap(node) end, diff --git a/moonscript/transform.moon b/moonscript/transform.moon index 57057442..e2703c20 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -42,7 +42,7 @@ is_singular = (body) -> if "group" == ntype body is_singular body[2] else - true + body[1] find_assigns = (body, out={}) -> for thing in *body @@ -697,11 +697,12 @@ class Accumulator } -- mutates the body of a loop construct to save last value into accumulator - -- can optionally skip nil results - mutate_body: (body, skip_nil=true) => - val = if not skip_nil and is_singular body - with body[1] - body = {} + mutate_body: (body) => + -- shortcut to write simpler code if body is a single expression + single_stm = is_singular body + val = if single_stm and types.is_value single_stm + body = {} + single_stm else body = apply_to_last body, (n) -> if types.is_value n @@ -719,14 +720,7 @@ class Accumulator {"update", @len_name, "+=", 1} } - if skip_nil - table.insert body, build["if"] { - cond: {"exp", @value_name, "!=", "nil"} - then: update - } - else - table.insert body, build.group update - + insert body, build.group update body default_accumulator = (node) => @@ -799,7 +793,7 @@ Value = Transformer { comprehension: (node) => a = Accumulator! node = @transform.statement node, (exp) -> - a\mutate_body {exp}, false + a\mutate_body {exp} a\wrap node tblcomprehension: (node) => diff --git a/test2.moon b/test2.moon index d2a64088..516c3071 100644 --- a/test2.moon +++ b/test2.moon @@ -84,7 +84,8 @@ output_fname = (base) -> describe "input tests", -> inputs = for file in lfs.dir options.in_dir - file\match options.input_pattern + with match = file\match options.input_pattern + continue unless match table.sort inputs diff --git a/tests/outputs/bubbling.lua b/tests/outputs/bubbling.lua index f054c1c2..651b0e2b 100644 --- a/tests/outputs/bubbling.lua +++ b/tests/outputs/bubbling.lua @@ -33,14 +33,10 @@ local j = (function() local _accum_0 = { } local _len_0 = 1 for i = 1, 10 do - local _value_0 - _value_0 = function(...) + _accum_0[_len_0] = function(...) return print(...) 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)() @@ -70,11 +66,8 @@ local x = (function(...) } for _index_0 = 1, #_list_0 do local i = _list_0[_index_0] - local _value_0 = i - if _value_0 ~= nil then - _accum_0[_len_0] = _value_0 - _len_0 = _len_0 + 1 - end + _accum_0[_len_0] = i + _len_0 = _len_0 + 1 end return _accum_0 end)(...) @@ -106,11 +99,8 @@ local a = (function(...) local _accum_0 = { } local _len_0 = 1 for i = 1, 10 do - local _value_0 = ... - if _value_0 ~= nil then - _accum_0[_len_0] = _value_0 - _len_0 = _len_0 + 1 - end + _accum_0[_len_0] = ... + _len_0 = _len_0 + 1 end return _accum_0 end)(...) @@ -118,14 +108,10 @@ local b = (function() local _accum_0 = { } local _len_0 = 1 for i = 1, 10 do - local _value_0 - _value_0 = function() + _accum_0[_len_0] = function() return print(...) 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)() \ No newline at end of file diff --git a/tests/outputs/loops.lua b/tests/outputs/loops.lua index 37c5fb63..87824e81 100644 --- a/tests/outputs/loops.lua +++ b/tests/outputs/loops.lua @@ -54,14 +54,10 @@ x = (function() local _list_1 = hello for _index_0 = 1, #_list_1 do local y = _list_1[_index_0] - local _value_0 if y % 2 == 0 then - _value_0 = y - end - if _value_0 ~= nil then - _accum_0[_len_0] = _value_0 - _len_0 = _len_0 + 1 + _accum_0[_len_0] = y end + _len_0 = _len_0 + 1 end return _accum_0 end)() @@ -76,11 +72,8 @@ local t = (function() local _accum_0 = { } local _len_0 = 1 for i = 10, 20 do - local _value_0 = i * 2 - if _value_0 ~= nil then - _accum_0[_len_0] = _value_0 - _len_0 = _len_0 + 1 - end + _accum_0[_len_0] = i * 2 + _len_0 = _len_0 + 1 end return _accum_0 end)() @@ -91,10 +84,8 @@ local y = (function() for j = 3, 30, 8 do hmm = hmm + 1 local _value_0 = j * hmm - if _value_0 ~= nil then - _accum_0[_len_0] = _value_0 - _len_0 = _len_0 + 1 - end + _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 end return _accum_0 end)() @@ -109,11 +100,8 @@ _ = function() local _accum_0 = { } local _len_0 = 1 for k = 10, 40 do - local _value_0 = "okay" - if _value_0 ~= nil then - _accum_0[_len_0] = _value_0 - _len_0 = _len_0 + 1 - end + _accum_0[_len_0] = "okay" + _len_0 = _len_0 + 1 end return _accum_0 end)() @@ -136,10 +124,8 @@ x = (function() while i < 10 do local _value_0 i = i + 1 - if _value_0 ~= nil then - _accum_0[_len_0] = _value_0 - _len_0 = _len_0 + 1 - end + _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 end return _accum_0 end)() @@ -151,10 +137,8 @@ x = (function() local thing = _list_1[_index_0] local _value_0 y = "hello" - if _value_0 ~= nil then - _accum_0[_len_0] = _value_0 - _len_0 = _len_0 + 1 - end + _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 end return _accum_0 end)() @@ -164,10 +148,8 @@ x = (function() for x = 1, 2 do local _value_0 y = "hello" - if _value_0 ~= nil then - _accum_0[_len_0] = _value_0 - _len_0 = _len_0 + 1 - end + _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 end return _accum_0 end)() @@ -214,10 +196,8 @@ local list = (function() break end local _value_0 = x - if _value_0 ~= nil then - _accum_0[_len_0] = _value_0 - _len_0 = _len_0 + 1 - end + _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 _continue_0 = true until true if not _continue_0 then From ff5317edec9894cb887fb436dc1c4b809e6b34a2 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 12 Jan 2013 14:09:14 -0800 Subject: [PATCH 066/554] update for changes to loop expressions #66 --- Makefile | 4 +++ moonscript/compile.lua | 46 ++++++++++++++++++++--------------- moonscript/compile.moon | 3 ++- moonscript/compile/value.lua | 7 ++---- moonscript/compile/value.moon | 4 +-- moonscript/transform.lua | 32 +++++++++++++++--------- moonscript/transform.moon | 2 +- 7 files changed, 58 insertions(+), 40 deletions(-) diff --git a/Makefile b/Makefile index 54dc37b7..930414c3 100644 --- a/Makefile +++ b/Makefile @@ -11,5 +11,9 @@ global: compile: bin/moonc moon/ moonscript/ + +compile_global: + moonc moon/ moonscript/ + watch: moonc -w moon/ moonscript/ diff --git a/moonscript/compile.lua b/moonscript/compile.lua index ed6b79a3..c0c1ebff 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -356,25 +356,33 @@ do local _len_0 = 1 local _list_0 = names for _index_0 = 1, #_list_0 do - local name = _list_0[_index_0] - local is_local = false - local real_name - local _exp_0 = mtype(name) - if LocalName == _exp_0 then - is_local = true - real_name = name:get_name(self) - elseif NameProxy == _exp_0 then - real_name = name:get_name(self) - elseif "string" == _exp_0 then - real_name = name - end - local _value_0 - if is_local or real_name and not self:has_name(real_name) then - _value_0 = real_name - end - if _value_0 ~= nil then - _accum_0[_len_0] = _value_0 - _len_0 = _len_0 + 1 + local _continue_0 = false + repeat + local name = _list_0[_index_0] + local is_local = false + local real_name + local _exp_0 = mtype(name) + if LocalName == _exp_0 then + is_local = true + real_name = name:get_name(self) + elseif NameProxy == _exp_0 then + real_name = name:get_name(self) + elseif "string" == _exp_0 then + real_name = name + end + if not (is_local or real_name and not self:has_name(real_name)) then + _continue_0 = true + break + end + local _value_0 = real_name + 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 + break end end return _accum_0 diff --git a/moonscript/compile.moon b/moonscript/compile.moon index 3eab6355..912e9d3c 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -216,7 +216,8 @@ class Block when NameProxy then name\get_name self when "string" then name - real_name if is_local or real_name and not @has_name real_name + continue unless is_local or real_name and not @has_name real_name + real_name @put_name name for name in *undeclared undeclared diff --git a/moonscript/compile/value.lua b/moonscript/compile/value.lua index f0a69283..b7078681 100644 --- a/moonscript/compile/value.lua +++ b/moonscript/compile/value.lua @@ -209,11 +209,8 @@ local value_compilers = { local _list_2 = args for _index_0 = 1, #_list_2 do local arg = _list_2[_index_0] - local _value_0 = arg[1] - if _value_0 ~= nil then - _accum_0[_len_0] = _value_0 - _len_0 = _len_0 + 1 - end + _accum_0[_len_0] = arg[1] + _len_0 = _len_0 + 1 end return _accum_0 end)() diff --git a/moonscript/compile/value.moon b/moonscript/compile/value.moon index faf4b916..52006edf 100644 --- a/moonscript/compile/value.moon +++ b/moonscript/compile/value.moon @@ -112,9 +112,9 @@ value_compilers = \stms block -- inject more args if the block manipulated arguments + -- only varargs bubbling does this currently if #args > #arg_names -- will only work for simple adjustments - arg_names = for arg in *args - arg[1] + arg_names = [arg[1] for arg in *args] .header = "function("..concat(arg_names, ", ")..")" diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 28684983..10a7d604 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -875,18 +875,26 @@ local Statement = Transformer({ local _len_0 = 1 local _list_1 = properties for _index_0 = 1, #_list_1 do - local tuple = _list_1[_index_0] - local key = tuple[1] - local _value_0 - if key[1] == "key_literal" and key[2] == constructor_name then - constructor = tuple[2] - _value_0 = nil - else - _value_0 = tuple - end - if _value_0 ~= nil then - _accum_0[_len_0] = _value_0 - _len_0 = _len_0 + 1 + local _continue_0 = false + repeat + local tuple = _list_1[_index_0] + local key = tuple[1] + local _value_0 + if key[1] == "key_literal" and key[2] == constructor_name then + constructor = tuple[2] + _continue_0 = true + break + else + _value_0 = tuple + end + 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 + break end end return _accum_0 diff --git a/moonscript/transform.moon b/moonscript/transform.moon index e2703c20..8901cbb0 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -486,7 +486,7 @@ Statement = Transformer { key = tuple[1] if key[1] == "key_literal" and key[2] == constructor_name constructor = tuple[2] - nil + continue else tuple From c4217982e091f5787784bb7c2557eb2c52703ab8 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 12 Jan 2013 14:09:43 -0800 Subject: [PATCH 067/554] rebuild --- moonscript/compile.lua | 6 ++-- moonscript/compile/value.lua | 6 ++-- moonscript/transform.lua | 43 +++++++++------------------- moonscript/transform/destructure.lua | 28 ++++++------------ moonscript/transform/names.lua | 10 ++----- moonscript/util.lua | 13 +++------ 6 files changed, 32 insertions(+), 74 deletions(-) diff --git a/moonscript/compile.lua b/moonscript/compile.lua index c0c1ebff..9084a4e4 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -375,10 +375,8 @@ do break end local _value_0 = real_name - if _value_0 ~= nil then - _accum_0[_len_0] = _value_0 - _len_0 = _len_0 + 1 - end + _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 _continue_0 = true until true if not _continue_0 then diff --git a/moonscript/compile/value.lua b/moonscript/compile/value.lua index b7078681..19a160f2 100644 --- a/moonscript/compile/value.lua +++ b/moonscript/compile/value.lua @@ -135,10 +135,8 @@ local value_compilers = { insert(default_args, arg) end local _value_0 = name - if _value_0 ~= nil then - _accum_0[_len_0] = _value_0 - _len_0 = _len_0 + 1 - end + _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 end return _accum_0 end)() diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 10a7d604..db428b57 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -66,16 +66,12 @@ 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 - _value_0 = fn(stm) + _accum_0[_len_0] = fn(stm) else - _value_0 = stm - end - if _value_0 ~= nil then - _accum_0[_len_0] = _value_0 - _len_0 = _len_0 + 1 + _accum_0[_len_0] = stm end + _len_0 = _len_0 + 1 end return _accum_0 end)() @@ -444,19 +440,15 @@ 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 - _value_0 = name + _accum_0[_len_0] = name else - _value_0 = { + _accum_0[_len_0] = { "dot", 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)() @@ -466,11 +458,8 @@ local Statement = Transformer({ local _list_0 = names for _index_0 = 1, #_list_0 do local name = _list_0[_index_0] - 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 + _accum_0[_len_0] = type(name) == "table" and name[2] or name + _len_0 = _len_0 + 1 end return _accum_0 end)() @@ -692,21 +681,17 @@ 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)) - _value_0 = _with_0 + _accum_0[_len_0] = _with_0 end else - _value_0 = name - end - if _value_0 ~= nil then - _accum_0[_len_0] = _value_0 - _len_0 = _len_0 + 1 + _accum_0[_len_0] = name end + _len_0 = _len_0 + 1 end return _accum_0 end)() @@ -887,10 +872,8 @@ local Statement = Transformer({ else _value_0 = tuple end - if _value_0 ~= nil then - _accum_0[_len_0] = _value_0 - _len_0 = _len_0 + 1 - end + _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 _continue_0 = true until true if not _continue_0 then diff --git a/moonscript/transform/destructure.lua b/moonscript/transform/destructure.lua index 6adb7293..3bc22ac3 100644 --- a/moonscript/transform/destructure.lua +++ b/moonscript/transform/destructure.lua @@ -166,11 +166,8 @@ split_assign = function(assign) local _accum_0 = { } local _len_0 = 1 for i = start, stop do - local _value_0 = names[i] - if _value_0 ~= nil then - _accum_0[_len_0] = _value_0 - _len_0 = _len_0 + 1 - end + _accum_0[_len_0] = names[i] + _len_0 = _len_0 + 1 end return _accum_0 end)(), @@ -178,11 +175,8 @@ split_assign = function(assign) local _accum_0 = { } local _len_0 = 1 for i = start, stop do - local _value_0 = values[i] - if _value_0 ~= nil then - _accum_0[_len_0] = _value_0 - _len_0 = _len_0 + 1 - end + _accum_0[_len_0] = values[i] + _len_0 = _len_0 + 1 end return _accum_0 end)() @@ -203,11 +197,8 @@ split_assign = function(assign) local _accum_0 = { } local _len_0 = 1 for i = start, total_names do - local _value_0 = names[i] - if _value_0 ~= nil then - _accum_0[_len_0] = _value_0 - _len_0 = _len_0 + 1 - end + _accum_0[_len_0] = names[i] + _len_0 = _len_0 + 1 end return _accum_0 end)() @@ -222,11 +213,8 @@ split_assign = function(assign) local _accum_0 = { } local _len_0 = 1 for i = start, total_values do - local _value_0 = values[i] - if _value_0 ~= nil then - _accum_0[_len_0] = _value_0 - _len_0 = _len_0 + 1 - end + _accum_0[_len_0] = values[i] + _len_0 = _len_0 + 1 end return _accum_0 end)() diff --git a/moonscript/transform/names.lua b/moonscript/transform/names.lua index 03faae34..5f439201 100644 --- a/moonscript/transform/names.lua +++ b/moonscript/transform/names.lua @@ -71,19 +71,15 @@ do } for _index_0 = 1, #_list_0 do local i = _list_0[_index_0] - local _value_0 if type(i) == "string" then - _value_0 = { + _accum_0[_len_0] = { "dot", i } else - _value_0 = i - end - if _value_0 ~= nil then - _accum_0[_len_0] = _value_0 - _len_0 = _len_0 + 1 + _accum_0[_len_0] = i end + _len_0 = _len_0 + 1 end return _accum_0 end)(...) diff --git a/moonscript/util.lua b/moonscript/util.lua index e8058451..54494659 100644 --- a/moonscript/util.lua +++ b/moonscript/util.lua @@ -104,11 +104,8 @@ dump = function(what) local _accum_0 = { } local _len_0 = 1 for k, v in pairs(what) do - local _value_0 = (" "):rep(depth * 4) .. "[" .. tostring(k) .. "] = " .. _dump(v, depth) - if _value_0 ~= nil then - _accum_0[_len_0] = _value_0 - _len_0 = _len_0 + 1 - end + _accum_0[_len_0] = (" "):rep(depth * 4) .. "[" .. tostring(k) .. "] = " .. _dump(v, depth) + _len_0 = _len_0 + 1 end return _accum_0 end)() @@ -148,10 +145,8 @@ debug_posmap = function(posmap, moon_code, lua_code) local lua_text = get_line(lua_code, lua_line) local moon_text = get_closest_line(moon_code, moon_line) local _value_0 = tostring(pos) .. "\t " .. tostring(lua_line) .. ":[ " .. tostring(trim(lua_text)) .. " ] >> " .. tostring(moon_line) .. ":[ " .. tostring(trim(moon_text)) .. " ]" - if _value_0 ~= nil then - _accum_0[_len_0] = _value_0 - _len_0 = _len_0 + 1 - end + _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 end return _accum_0 end)() From 0cf96b97f64ee4e3de95e72b1e96f0904775abe7 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 12 Jan 2013 15:09:17 -0800 Subject: [PATCH 068/554] 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 53107818..c5549f69 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 23ae998d..6a506ccb 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 db428b57..ed4c8815 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 8901cbb0..d27b6e28 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 6822c844..345d5b70 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 262945c7..6e3a09bf 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 0598efe3..4ac5530a 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 75b5bc1f..893787af 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 From 1bff5ea9beb69bd49e418316cddf3f5d047eb81c Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 12 Jan 2013 15:18:44 -0800 Subject: [PATCH 069/554] oops, rebuild --- moonscript/transform.lua | 43 ++++++++++++---------------------------- 1 file changed, 13 insertions(+), 30 deletions(-) diff --git a/moonscript/transform.lua b/moonscript/transform.lua index ed4c8815..590aff19 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -66,16 +66,12 @@ 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 - _value_0 = fn(stm) + _accum_0[_len_0] = fn(stm) else - _value_0 = stm - end - if _value_0 ~= nil then - _accum_0[_len_0] = _value_0 - _len_0 = _len_0 + 1 + _accum_0[_len_0] = stm end + _len_0 = _len_0 + 1 end return _accum_0 end)() @@ -463,19 +459,15 @@ 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 - _value_0 = name + _accum_0[_len_0] = name else - _value_0 = { + _accum_0[_len_0] = { "dot", 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)() @@ -485,11 +477,8 @@ local Statement = Transformer({ local _list_0 = names for _index_0 = 1, #_list_0 do local name = _list_0[_index_0] - 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 + _accum_0[_len_0] = type(name) == "table" and name[2] or name + _len_0 = _len_0 + 1 end return _accum_0 end)() @@ -711,21 +700,17 @@ 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)) - _value_0 = _with_0 + _accum_0[_len_0] = _with_0 end else - _value_0 = name - end - if _value_0 ~= nil then - _accum_0[_len_0] = _value_0 - _len_0 = _len_0 + 1 + _accum_0[_len_0] = name end + _len_0 = _len_0 + 1 end return _accum_0 end)() @@ -906,10 +891,8 @@ local Statement = Transformer({ else _value_0 = tuple end - if _value_0 ~= nil then - _accum_0[_len_0] = _value_0 - _len_0 = _len_0 + 1 - end + _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 _continue_0 = true until true if not _continue_0 then From d772547d59436fa56587e1250ef2a44932fc9fd2 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 13 Jan 2013 11:50:26 -0800 Subject: [PATCH 070/554] update export tests --- tests/inputs/export.moon | 62 ++++++++++-------- tests/outputs/export.lua | 138 +++++++++++++++++++++------------------ 2 files changed, 108 insertions(+), 92 deletions(-) diff --git a/tests/inputs/export.moon b/tests/inputs/export.moon index 8889ceab..aab06a48 100644 --- a/tests/inputs/export.moon +++ b/tests/inputs/export.moon @@ -1,44 +1,50 @@ -export a,b,c = 223, 343 -export cool = "dad" +do + export a,b,c = 223, 343 + export cool = "dad" -export class Something - umm: "cool" +do + export class Something + umm: "cool" -What = if this - 232 -else - 4343 +do + export a,b,c + a,b,c,d = "hello" -export a,b,c -a,b,c,d = "hello" +do + What = if this + 232 + else + 4343 -export ^ + export ^ -another = 3434 -Another = 7890 + another = 3434 + Another = 7890 -if inner then Yeah = "10000" + if inner then Yeah = "10000" -What = if this - 232 -else - 4343 + What = if this + 232 + else + 4343 -export * -What = if this - 232 -else - 4343 +do + export * -x,y,z = 1,2,3 + What = if this + 232 + else + 4343 -y = -> - hallo = 3434 + x,y,z = 1,2,3 -with tmp - j = 2000 + y = -> + hallo = 3434 + + with tmp + j = 2000 diff --git a/tests/outputs/export.lua b/tests/outputs/export.lua index a609aea4..e6c9a3e9 100644 --- a/tests/outputs/export.lua +++ b/tests/outputs/export.lua @@ -1,73 +1,83 @@ -a, b, c = 223, 343 -cool = "dad" do - local _parent_0 = nil - local _base_0 = { - umm = "cool" - } - _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end - local _class_0 = setmetatable({ - __init = function(self, ...) - if _parent_0 then - return _parent_0.__init(self, ...) - end - end, - __base = _base_0, - __name = "Something", - __parent = _parent_0 - }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val + a, b, c = 223, 343 + cool = "dad" +end +do + do + local _parent_0 = nil + local _base_0 = { + umm = "cool" + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, ...) + if _parent_0 then + return _parent_0.__init(self, ...) + end + end, + __base = _base_0, + __name = "Something", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 end - end, - __call = function(cls, ...) - local _self_0 = setmetatable({}, _base_0) - cls.__init(_self_0, ...) - return _self_0 + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) end - }) - _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) + Something = _class_0 end - Something = _class_0 -end -local What -if this then - What = 232 -else - What = 4343 -end -local d -a, b, c, d = "hello" -local another = 3434 -Another = 7890 -if inner then - local Yeah = "10000" -end -if this then - What = 232 -else - What = 4343 end -if this then - What = 232 -else - What = 4343 +do + local d + a, b, c, d = "hello" end -x, y, z = 1, 2, 3 -y = function() - local hallo = 3434 +do + local What + if this then + What = 232 + else + What = 4343 + end + local another = 3434 + Another = 7890 + if inner then + local Yeah = "10000" + end + if this then + What = 232 + else + What = 4343 + end end do - local _with_0 = tmp - local j = 2000 - return _with_0 + if this then + local What = 232 + else + local What = 4343 + end + x, y, z = 1, 2, 3 + y = function() + local hallo = 3434 + end + do + local _with_0 = tmp + local j = 2000 + return _with_0 + end end \ No newline at end of file From cad4aea61068b798560afc82b73a1e72be9d4076 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 13 Jan 2013 12:11:47 -0800 Subject: [PATCH 071/554] put exported declared names so they can be assigned in deeper scopes --- moonscript/compile.lua | 29 ++++++++++++++++------------- moonscript/compile.moon | 14 +++++++++----- moonscript/transform.moon | 1 + tests/inputs/export.moon | 27 +++++++++++++++++++++++++++ tests/outputs/export.lua | 30 +++++++++++++++++++++++++++--- 5 files changed, 80 insertions(+), 21 deletions(-) diff --git a/moonscript/compile.lua b/moonscript/compile.lua index 9084a4e4..b38433a3 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -370,7 +370,12 @@ do elseif "string" == _exp_0 then real_name = name end - if not (is_local or real_name and not self:has_name(real_name)) then + if not (is_local or real_name and not self:has_name(real_name, true)) then + _continue_0 = true + break + end + self:put_name(real_name) + if self:name_exported(real_name) then _continue_0 = true break end @@ -385,16 +390,19 @@ do end return _accum_0 end)() - local _list_0 = undeclared - for _index_0 = 1, #_list_0 do - local name = _list_0[_index_0] - self:put_name(name) - end return undeclared end, whitelist_names = function(self, names) self._name_whitelist = Set(names) end, + name_exported = function(self, name) + if self.export_all then + return true + end + if self.export_proper and name:match("^%u") then + return true + end + end, put_name = function(self, name, ...) local value = ... if select("#", ...) == 0 then @@ -406,13 +414,8 @@ do self._names[name] = value end, has_name = function(self, name, skip_exports) - if not skip_exports then - if self.export_all then - return true - end - if self.export_proper and name:match("^%u") then - return true - end + if not skip_exports and self:name_exported(name) then + return true end local yes = self._names[name] if yes == nil and self.parent then diff --git a/moonscript/compile.moon b/moonscript/compile.moon index 912e9d3c..13be4c7d 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -216,15 +216,21 @@ class Block when NameProxy then name\get_name self when "string" then name - continue unless is_local or real_name and not @has_name real_name + continue unless is_local or real_name and not @has_name real_name, true + -- put exported names so they can be assigned to in deeper scope + @put_name real_name + continue if @name_exported real_name real_name - @put_name name for name in *undeclared undeclared whitelist_names: (names) => @_name_whitelist = Set names + name_exported: (name) => + return true if @export_all + return true if @export_proper and name\match"^%u" + put_name: (name, ...) => value = ... value = true if select("#", ...) == 0 @@ -233,9 +239,7 @@ class Block @_names[name] = value has_name: (name, skip_exports) => - if not skip_exports - return true if @export_all - return true if @export_proper and name\match"^%u" + return true if not skip_exports and @name_exported name yes = @_names[name] if yes == nil and @parent diff --git a/moonscript/transform.moon b/moonscript/transform.moon index d27b6e28..39a0cdf9 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -195,6 +195,7 @@ Statement = Transformer { if destructure.has_destructure names return destructure.split_assign node + -- print util.dump node node continue: (node) => diff --git a/tests/inputs/export.moon b/tests/inputs/export.moon index aab06a48..0a563798 100644 --- a/tests/inputs/export.moon +++ b/tests/inputs/export.moon @@ -48,3 +48,30 @@ do j = 2000 +do + export * + x = 3434 + if y then + x = 10 + +do + export * + if y then + x = 10 + x = 3434 + +do + do + export * + + k = 1212 + + do + h = 100 + + y = -> + h = 100 + k = 100 + + h = 100 + diff --git a/tests/outputs/export.lua b/tests/outputs/export.lua index e6c9a3e9..44ac1e8e 100644 --- a/tests/outputs/export.lua +++ b/tests/outputs/export.lua @@ -67,9 +67,9 @@ do end do if this then - local What = 232 + What = 232 else - local What = 4343 + What = 4343 end x, y, z = 1, 2, 3 y = function() @@ -78,6 +78,30 @@ do do local _with_0 = tmp local j = 2000 - return _with_0 end +end +do + x = 3434 + if y then + x = 10 + end +end +do + if y then + local x = 10 + end + x = 3434 +end +do + do + k = 1212 + do + local h = 100 + end + y = function() + local h = 100 + k = 100 + end + end + local h = 100 end \ No newline at end of file From e075c2f9716766d8a7e5eb80e56fbda302f1b579 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 13 Jan 2013 12:23:49 -0800 Subject: [PATCH 072/554] local * doesn't grab names in nested scopes --- moonscript/compile.lua | 3 +++ moonscript/compile.moon | 3 +++ moonscript/transform.lua | 2 +- moonscript/transform.moon | 2 +- tests/inputs/local.moon | 17 +++++++++++++++++ tests/outputs/local.lua | 16 ++++++++++++++++ 6 files changed, 41 insertions(+), 2 deletions(-) diff --git a/moonscript/compile.lua b/moonscript/compile.lua index b38433a3..a99c9788 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -336,6 +336,9 @@ do get = function(self, name) return self._state[name] end, + get_current = function(self, name) + return rawget(self._state, name) + end, listen = function(self, name, fn) self._listeners[name] = fn end, diff --git a/moonscript/compile.moon b/moonscript/compile.moon index 13be4c7d..385b9375 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -196,6 +196,9 @@ class Block get: (name) => @_state[name] + get_current: (name) => + rawget @_state, name + listen: (name, fn) => @_listeners[name] = fn diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 590aff19..7ed265e3 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -345,7 +345,7 @@ local Statement = Transformer({ assign = function(self, node) local names, values = unpack(node, 2) do - local globber = self:get("name_glob") + local globber = self:get_current("name_glob") if globber then local _list_0 = names for _index_0 = 1, #_list_0 do diff --git a/moonscript/transform.moon b/moonscript/transform.moon index 39a0cdf9..da886116 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -164,7 +164,7 @@ Statement = Transformer { assign: (node) => names, values = unpack node, 2 - if globber = @get "name_glob" + if globber = @get_current "name_glob" for name in *names if globber name @put_name name diff --git a/tests/inputs/local.moon b/tests/inputs/local.moon index ba1a8001..3b02c290 100644 --- a/tests/inputs/local.moon +++ b/tests/inputs/local.moon @@ -33,3 +33,20 @@ do local * x,y = "a", "b" + +do + local * + if something + x = 2323 + +-- this is broken +do + local * + do + x = "one" + + x = 100 + + do + x = "two" + diff --git a/tests/outputs/local.lua b/tests/outputs/local.lua index 830b7b03..936f85de 100644 --- a/tests/outputs/local.lua +++ b/tests/outputs/local.lua @@ -30,4 +30,20 @@ end do local x, y x, y = "a", "b" +end +do + + if something then + x = 2323 + end +end +do + local x + do + x = "one" + end + x = 100 + do + x = "two" + end end \ No newline at end of file From f56095256bee7497c5dce071a6ec1d272a8ab52b Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 13 Jan 2013 14:05:16 -0800 Subject: [PATCH 073/554] extract declarations in transform instead of delayed line --- moonscript/compile.lua | 21 +++++----- moonscript/compile.moon | 13 +++++- moonscript/compile/statement.lua | 34 ---------------- moonscript/compile/statement.moon | 27 ------------- moonscript/transform.lua | 67 ++++++++++++++++++++++++++----- moonscript/transform.moon | 29 ++++++++++--- tests/inputs/local.moon | 40 ++++++++++++++---- tests/outputs/local.lua | 54 ++++++++++++++++++------- 8 files changed, 177 insertions(+), 108 deletions(-) diff --git a/moonscript/compile.lua b/moonscript/compile.lua index a99c9788..60087495 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -582,11 +582,18 @@ do if ret then error("deprecated stms call, use transformer") end - local _list_0 = stms - for _index_0 = 1, #_list_0 do - local stm = _list_0[_index_0] - self:stm(stm) + local current_stms, current_stm_i + do + local _obj_0 = self + current_stms, current_stm_i = _obj_0.current_stms, _obj_0.current_stm_i + end + self.current_stms = stms + for i = 1, #stms do + self.current_stm_i = i + self:stm(stms[i]) end + self.current_stms = current_stms + self.current_stm_i = current_stm_i return nil end, splice = function(self, fn) @@ -663,11 +670,7 @@ do if not (self.options.implicitly_return_root == false) then stms = transform.Statement.transformers.root_stms(self, stms) end - local _list_0 = stms - for _index_0 = 1, #_list_0 do - local s = _list_0[_index_0] - self:stm(s) - end + return self:stms(stms) end, render = function(self) local buffer = self._lines:flatten() diff --git a/moonscript/compile.moon b/moonscript/compile.moon index 385b9375..c335b9e5 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -356,7 +356,16 @@ class Block stms: (stms, ret) => error "deprecated stms call, use transformer" if ret - @stm stm for stm in *stms + {:current_stms, :current_stm_i} = @ + + @current_stms = stms + for i=1,#stms + @current_stm_i = i + @stm stms[i] + + @current_stms = current_stms + @current_stm_i = current_stm_i + nil splice: (fn) => @@ -374,7 +383,7 @@ class RootBlock extends Block root_stms: (stms) => unless @options.implicitly_return_root == false stms = transform.Statement.transformers.root_stms self, stms - @stm s for s in *stms + @stms stms render: => -- print @_lines diff --git a/moonscript/compile/statement.lua b/moonscript/compile/statement.lua index 9cfb2ce7..afdcf888 100644 --- a/moonscript/compile/statement.lua +++ b/moonscript/compile/statement.lua @@ -39,40 +39,6 @@ local statement_compilers = { end end end, - declare_glob = function(self, node) - local kind = node[2] - local names = { } - local fn - local _exp_0 = node[2] - if "*" == _exp_0 then - fn = function(name) - if type(name) == "string" then - insert(names, name) - return true - end - end - elseif "^" == _exp_0 then - fn = function(name) - if type(name) == "string" and name:match("^%u") then - insert(names, name) - return true - end - end - else - fn = error("unknown glob") - end - self:set("name_glob", fn) - return data.DelayedLine(function(buff) - insert(buff, "local ") - local _list_0 = names - for _index_0 = 1, #_list_0 do - local name = _list_0[_index_0] - insert(buff, self:name(name)) - insert(buff, ", ") - end - buff[#buff] = nil - end) - end, declare_with_shadows = function(self, node) local names = node[2] self:declare(names) diff --git a/moonscript/compile/statement.moon b/moonscript/compile/statement.moon index 72ce9ae1..e48e3978 100644 --- a/moonscript/compile/statement.moon +++ b/moonscript/compile/statement.moon @@ -20,33 +20,6 @@ statement_compilers = with @line "local " \append_list [@name name for name in *undeclared], ", " - declare_glob: (node) => - kind = node[2] - - names = {} - fn = switch node[2] - when "*" - (name) -> - if type(name) == "string" - insert names, name - true - when "^" - (name) -> - if type(name) == "string" and name\match "^%u" - insert names, name - true - else - error "unknown glob" - - @set "name_glob", fn - - data.DelayedLine (buff) -> - insert buff, "local " - for name in *names - insert buff, @name name - insert buff, ", " - buff[#buff] = nil -- strips local if no names - -- this overrides the existing names with new locals, used for local keyword declare_with_shadows: (node) => names = node[2] diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 7ed265e3..2e9353e5 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -127,6 +127,35 @@ hoist_declarations = function(body) assigns }) end +local extract_declarations +extract_declarations = function(self, body, start, out) + if body == nil then + body = self.current_stms + end + if start == nil then + start = self.current_stm_i + 1 + end + if out == nil then + out = { } + end + for i = start, #body do + local stm = self.transform.statement(body[i]) + body[i] = stm + local _exp_0 = stm[1] + if "assign" == _exp_0 or "declare" == _exp_0 then + local _list_0 = stm[2] + for _index_0 = 1, #_list_0 do + local name = _list_0[_index_0] + if type(name) == "string" then + insert(out, name) + end + end + elseif "group" == _exp_0 then + extract_declarations(self, stm[2], 1, out) + end + end + return out +end local expand_elseif_assign expand_elseif_assign = function(ifstm) for i = 4, #ifstm do @@ -342,20 +371,40 @@ local Statement = Transformer({ root_stms = function(self, body) return apply_to_last(body, implicitly_return(self)) end, - assign = function(self, node) - local names, values = unpack(node, 2) - do - local globber = self:get_current("name_glob") - if globber then + declare_glob = function(self, node) + local names = extract_declarations(self) + if node[2] == "^" then + names = (function() + local _accum_0 = { } + local _len_0 = 1 local _list_0 = names for _index_0 = 1, #_list_0 do - local name = _list_0[_index_0] - if globber(name) then - self:put_name(name) + local _continue_0 = false + repeat + local name = _list_0[_index_0] + if not (name:match("^%u")) then + _continue_0 = true + break + end + local _value_0 = name + _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 + _continue_0 = true + until true + if not _continue_0 then + break end end - end + return _accum_0 + end)() end + return { + "declare", + names + } + end, + assign = function(self, node) + local names, values = unpack(node, 2) local transformed if #values == 1 then local value = values[1] diff --git a/moonscript/transform.moon b/moonscript/transform.moon index da886116..08bcefd9 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -67,6 +67,20 @@ hoist_declarations = (body) -> table.insert body, idx, {"declare", assigns} + +-- this mutates body searching for assigns +extract_declarations = (body=@current_stms, start=@current_stm_i + 1, out={}) => + for i=start,#body + stm = @transform.statement body[i] + body[i] = stm + switch stm[1] + when "assign", "declare" + for name in *stm[2] + insert out, name if type(name) == "string" + when "group" + extract_declarations @, stm[2], 1, out + out + expand_elseif_assign = (ifstm) -> for i = 4, #ifstm case = ifstm[i] @@ -161,14 +175,19 @@ Statement = Transformer { root_stms: (body) => apply_to_last body, implicitly_return @ + declare_glob: (node) => + names = extract_declarations @ + + if node[2] == "^" + names = for name in *names + continue unless name\match "^%u" + name + + {"declare", names} + assign: (node) => names, values = unpack node, 2 - if globber = @get_current "name_glob" - for name in *names - if globber name - @put_name name - -- bubble cascading assigns transformed = if #values == 1 value = values[1] diff --git a/tests/inputs/local.moon b/tests/inputs/local.moon index 3b02c290..7b7e8907 100644 --- a/tests/inputs/local.moon +++ b/tests/inputs/local.moon @@ -1,13 +1,16 @@ -local a -local a,b,c +do + local a + local a,b,c + b,g = 23232 -x = 1212 -something = -> - local x - x = 1212 +do + x = 1212 + something = -> + local x + x = 1212 do local * @@ -39,7 +42,6 @@ do if something x = 2323 --- this is broken do local * do @@ -50,3 +52,27 @@ do do x = "two" +do + local * + k = if what + 10 + x = 100 + + {:a,:b, :c} = y + + +do + local * + + a = 100 + print "hi" + b = 200 + + local * + c = 100 + print "hi" + d = 200 + d = 2323 + + +g = 2323 -- test if anything leaked diff --git a/tests/outputs/local.lua b/tests/outputs/local.lua index 936f85de..3d908ad6 100644 --- a/tests/outputs/local.lua +++ b/tests/outputs/local.lua @@ -1,10 +1,16 @@ -local a -local a, b, c -local x = 1212 -local something -something = function() - local x - x = 1212 +do + local a + local a, b, c + local g + b, g = 23232 +end +do + local x = 1212 + local something + something = function() + local x + x = 1212 + end end do local y, z @@ -12,29 +18,25 @@ do z = 2323 end do - print("Nothing Here!") end do local X, Y - x = 3434 + local x = 3434 local y = 3434 X = 3434 Y = "yeah" end do - - local y - x, y = "a", "b" + local x, y = "a", "b" end do local x, y x, y = "a", "b" end do - if something then - x = 2323 + local x = 2323 end end do @@ -46,4 +48,26 @@ do do x = "two" end -end \ No newline at end of file +end +do + local k, x, a, b, c + if what then + k = 10 + end + x = 100 + do + local _obj_0 = y + a, b, c = _obj_0.a, _obj_0.b, _obj_0.c + end +end +do + local a, b, c, d + a = 100 + print("hi") + b = 200 + c = 100 + print("hi") + d = 200 + d = 2323 +end +local g = 2323 \ No newline at end of file From 1e84b5d9ff1bb21a961e21888a1abadf6aa8d674 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 13 Jan 2013 14:10:21 -0800 Subject: [PATCH 074/554] replace hoist_declarations with declare_glob in classes, fixes #65 --- moonscript/transform.lua | 45 ++++---------------------------------- moonscript/transform.moon | 28 ++---------------------- tests/inputs/class.moon | 11 ++++++++++ tests/outputs/class.lua | 46 +++++++++++++++++++++++++++++++++++++-- 4 files changed, 61 insertions(+), 69 deletions(-) diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 2e9353e5..62502a97 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -87,46 +87,6 @@ is_singular = function(body) return body[1] end end -local find_assigns -find_assigns = function(body, out) - if out == nil then - out = { } - end - local _list_0 = body - for _index_0 = 1, #_list_0 do - local thing = _list_0[_index_0] - local _exp_0 = thing[1] - if "group" == _exp_0 then - find_assigns(thing[2], out) - elseif "assign" == _exp_0 then - table.insert(out, thing[2]) - end - end - return out -end -local hoist_declarations -hoist_declarations = function(body) - local assigns = { } - local _list_0 = find_assigns(body) - for _index_0 = 1, #_list_0 do - local names = _list_0[_index_0] - local _list_1 = names - for _index_1 = 1, #_list_1 do - local name = _list_1[_index_1] - if type(name) == "string" then - table.insert(assigns, name) - end - end - end - local idx = 1 - while mtype(body[idx]) == Run do - idx = idx + 1 - end - return table.insert(body, idx, { - "declare", - assigns - }) -end local extract_declarations extract_declarations = function(self, body, start, out) if body == nil then @@ -1194,6 +1154,10 @@ local Statement = Transformer({ end end) end), + { + "declare_glob", + "*" + }, _with_0.assign_one(parent_cls_name, parent_val == "" and "nil" or parent_val), _with_0.assign_one(base_name, { "table", @@ -1261,7 +1225,6 @@ local Statement = Transformer({ end end)() } - hoist_declarations(out_body) value = _with_0.group({ _with_0.group((function() if ntype(name) == "value" then diff --git a/moonscript/transform.moon b/moonscript/transform.moon index 08bcefd9..aa603108 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -44,30 +44,6 @@ is_singular = (body) -> else body[1] -find_assigns = (body, out={}) -> - for thing in *body - switch thing[1] - when "group" - find_assigns thing[2], out - when "assign" - table.insert out, thing[2] -- extract names - out - -hoist_declarations = (body) -> - assigns = {} - - -- hoist the plain old assigns - for names in *find_assigns body - for name in *names - table.insert assigns, name if type(name) == "string" - - -- insert after runs - idx = 1 - while mtype(body[idx]) == Run do idx += 1 - - table.insert body, idx, {"declare", assigns} - - -- this mutates body searching for assigns extract_declarations = (body=@current_stms, start=@current_stm_i + 1, out={}) => for i=start,#body @@ -640,6 +616,8 @@ Statement = Transformer { else parent_cls_name + {"declare_glob", "*"} + .assign_one parent_cls_name, parent_val == "" and "nil" or parent_val .assign_one base_name, {"table", properties} .assign_one base_name\chain"__index", base_name @@ -685,8 +663,6 @@ Statement = Transformer { ret cls_name } - hoist_declarations out_body - value = .group { .group if ntype(name) == "value" then { .declare names: {name} diff --git a/tests/inputs/class.moon b/tests/inputs/class.moon index 0deb37e8..2cc1d43a 100644 --- a/tests/inputs/class.moon +++ b/tests/inputs/class.moon @@ -162,3 +162,14 @@ class Something nil +-- + +-- hoisting +class Something + val = 23 + {:insert} = table + new: => print insert, val -- prints nil 23 + +-- + +nil diff --git a/tests/outputs/class.lua b/tests/outputs/class.lua index 2156f398..686d7f94 100644 --- a/tests/outputs/class.lua +++ b/tests/outputs/class.lua @@ -987,5 +987,47 @@ do _parent_0.__inherited(_parent_0, _class_0) end Something = _class_0 - return _class_0 -end \ No newline at end of file +end +do + local val, insert + local _parent_0 = nil + local _base_0 = { } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + return print(insert, val) + end, + __base = _base_0, + __name = "Something", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + val = 23 + do + local _obj_0 = table + insert = _obj_0.insert + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Something = _class_0 +end +return nil \ No newline at end of file From f9a2c1b2d7285134c90f747fb72703f133ca466b Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 13 Jan 2013 14:13:04 -0800 Subject: [PATCH 075/554] run tests under 5.1 normally --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 930414c3..20b1b607 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ test:: - TIME=1 bin/moon test2.moon + TIME=1 lua5.1 bin/moon test2.moon local: luarocks make --local moonscript-dev-1.rockspec From a44c5ac27f27b331663005358b337339b6d6b8a7 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 13 Jan 2013 23:38:38 -0800 Subject: [PATCH 076/554] fix filename globbing --- bin/moonc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/moonc b/bin/moonc index 1601d9ce..d99f228f 100755 --- a/bin/moonc +++ b/bin/moonc @@ -178,7 +178,7 @@ function scan_directory(root, collected) scan_directory(full_path, collected) end - if fname:match(".moon") then + if fname:match("%.moon$") then table.insert(collected, full_path) end end From af2c443807696b5cd5c3cacbcf60aac0d32d6e56 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 23 Jan 2013 17:50:36 -0800 Subject: [PATCH 077/554] don't alter class constructor at all --- moonscript/transform.lua | 7 ++----- moonscript/transform.moon | 7 ++----- tests/inputs/class.moon | 3 +++ tests/outputs/class.lua | 33 +++++++++++++++++++++++++++++++++ 4 files changed, 40 insertions(+), 10 deletions(-) diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 62502a97..2fe751ba 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -882,7 +882,7 @@ local Statement = Transformer({ end end end - local constructor = nil + local constructor properties = (function() local _accum_0 = { } local _len_0 = 1 @@ -914,7 +914,7 @@ local Statement = Transformer({ local base_name = NameProxy("base") local self_name = NameProxy("self") local cls_name = NameProxy("class") - if not constructor then + if not (constructor) then constructor = build.fndef({ args = { { @@ -939,9 +939,6 @@ local Statement = Transformer({ }) } }) - else - smart_node(constructor) - constructor.arrow = "fat" end local real_name = name or parent_assign and parent_assign[2][1] local _exp_0 = ntype(real_name) diff --git a/moonscript/transform.moon b/moonscript/transform.moon index aa603108..de7419b7 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -482,7 +482,7 @@ Statement = Transformer { insert properties, tuple -- find constructor - constructor = nil + local constructor properties = for tuple in *properties key = tuple[1] if key[1] == "key_literal" and key[2] == constructor_name @@ -496,7 +496,7 @@ Statement = Transformer { self_name = NameProxy "self" cls_name = NameProxy "class" - if not constructor + unless constructor constructor = build.fndef { args: {{"..."}} arrow: "fat" @@ -509,9 +509,6 @@ Statement = Transformer { } } } - else - smart_node constructor - constructor.arrow = "fat" real_name = name or parent_assign and parent_assign[2][1] real_name = switch ntype real_name diff --git a/tests/inputs/class.moon b/tests/inputs/class.moon index 2cc1d43a..1d27e5e5 100644 --- a/tests/inputs/class.moon +++ b/tests/inputs/class.moon @@ -172,4 +172,7 @@ class Something -- +class X + new: hi + nil diff --git a/tests/outputs/class.lua b/tests/outputs/class.lua index 686d7f94..e65b1910 100644 --- a/tests/outputs/class.lua +++ b/tests/outputs/class.lua @@ -1030,4 +1030,37 @@ do end Something = _class_0 end +do + local _parent_0 = nil + local _base_0 = { } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = hi, + __base = _base_0, + __name = "X", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + X = _class_0 +end return nil \ No newline at end of file From c9b121c04617db2a58972b312b33180eb6ef86b5 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 23 Jan 2013 18:02:21 -0800 Subject: [PATCH 078/554] extract declarations doesn't puke on nil statement in body --- moonscript/transform.lua | 34 +++++++++++++++++++++++----------- moonscript/transform.moon | 4 +++- tests/inputs/local.moon | 5 +++++ tests/outputs/local.lua | 7 +++++++ 4 files changed, 38 insertions(+), 12 deletions(-) diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 2fe751ba..42473539 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -99,19 +99,31 @@ extract_declarations = function(self, body, start, out) out = { } end for i = start, #body do - local stm = self.transform.statement(body[i]) - body[i] = stm - local _exp_0 = stm[1] - if "assign" == _exp_0 or "declare" == _exp_0 then - local _list_0 = stm[2] - for _index_0 = 1, #_list_0 do - local name = _list_0[_index_0] - if type(name) == "string" then - insert(out, name) + local _continue_0 = false + repeat + local stm = body[i] + if stm == nil then + _continue_0 = true + break + end + stm = self.transform.statement(stm) + body[i] = stm + local _exp_0 = stm[1] + if "assign" == _exp_0 or "declare" == _exp_0 then + local _list_0 = stm[2] + for _index_0 = 1, #_list_0 do + local name = _list_0[_index_0] + if type(name) == "string" then + insert(out, name) + end end + elseif "group" == _exp_0 then + extract_declarations(self, stm[2], 1, out) end - elseif "group" == _exp_0 then - extract_declarations(self, stm[2], 1, out) + _continue_0 = true + until true + if not _continue_0 then + break end end return out diff --git a/moonscript/transform.moon b/moonscript/transform.moon index de7419b7..c8e9531b 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -47,7 +47,9 @@ is_singular = (body) -> -- this mutates body searching for assigns extract_declarations = (body=@current_stms, start=@current_stm_i + 1, out={}) => for i=start,#body - stm = @transform.statement body[i] + stm = body[i] + continue if stm == nil + stm = @transform.statement stm body[i] = stm switch stm[1] when "assign", "declare" diff --git a/tests/inputs/local.moon b/tests/inputs/local.moon index 7b7e8907..d4a616ca 100644 --- a/tests/inputs/local.moon +++ b/tests/inputs/local.moon @@ -75,4 +75,9 @@ do d = 2323 +do + local * + -- this generates a nil value in the body + for a in *{} do a + g = 2323 -- test if anything leaked diff --git a/tests/outputs/local.lua b/tests/outputs/local.lua index 3d908ad6..db19697a 100644 --- a/tests/outputs/local.lua +++ b/tests/outputs/local.lua @@ -70,4 +70,11 @@ do d = 200 d = 2323 end +do + local _list_0 = { } + for _index_0 = 1, #_list_0 do + local a = _list_0[_index_0] + local _ = a + end +end local g = 2323 \ No newline at end of file From e0a6d4f44d98c33304208c501c3553dc62d6e799 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 23 Jan 2013 18:59:42 -0800 Subject: [PATCH 079/554] some destructuring docs --- docs/reference.md | 76 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/docs/reference.md b/docs/reference.md index c5549f69..830aa982 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -1293,6 +1293,82 @@ statement in its body. } ``` +## Destructuring Assignment + +Destructuring assignment is a way to quickly extract values from a table by +their name or position in array based tables. + +Typically when you see a table literal, `{1,2,3}`, it is on the right hand side +of an assignment because it is a value. Destructuring assignment swaps the role +of the table literal, and puts it on the left hand side of an assign +statement. + +This is best explained with examples. Here is how you would unpack the first +two values from a table: + + ```moon + thing = {1,2} + + {a,b} = thing + print a,b + ``` + +In the destructuring table literal, the key represents the key to read from the +right hand side, and the value represents the name the read value will be +assigned to. + + ```moon + obj = { + hello: "world" + day: "tuesday" + length: 20 + } + + {hello: hello, day: the_day} = obj + print hello, the_day + ``` + +This also works with nested data structures as well: + + ```moon + obj2 = { + numbers: {1,2,3,4} + properties: { + color: "green" + height: 13.5 + } + } + + {numbers: {first, second}} = obj2 + print first, second, color + ``` +If the destructuring statement is complicated, feel free to spread it out over +a few lines. A slightly more complicated example: + + ```moon + { + numbers: { first, second } + properties: { + color: color + } + } = obj2 + ``` + +It's common to extract values from at table and assign them the local variables +that have the same name as the key. In order to avoid repetition we can use the +`:` prefix operator: + + ```moon + {:concat, :insert} = table + ``` + +This is effectively the same as import, but we can rename fields we want to +extract by mixing the syntax: + + ```moon + {:mix, :max, random: rand } = math + ``` + ## Function Stubs It is common to pass a function from an object around as a value, for example, From f75ebb80a6154840feabe6f91bb2d753c68555d2 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 24 Jan 2013 15:20:06 -0800 Subject: [PATCH 080/554] numbers can start with . --- moonscript/parse.lua | 5 ++++- tests/inputs/literals.moon | 4 ++++ tests/outputs/literals.lua | 3 +++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 6a506ccb..37f15b7b 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -52,7 +52,10 @@ local _Name = C(R("az", "AZ", "__") * AlphaNum^0) local Name = Space * _Name local Num = P"0x" * R("09", "af", "AF")^1 + - R"09"^1 * (P"." * R"09"^1)^-1 * (S"eE" * P"-"^-1 * R"09"^1)^-1 + ( + R"09"^1 * (P"." * R"09"^1)^-1 + + P"." * R"09"^1 + ) * (S"eE" * P"-"^-1 * R"09"^1)^-1 Num = Space * (Num / function(value) return {"number", value} end) diff --git a/tests/inputs/literals.moon b/tests/inputs/literals.moon index ef808289..125b494e 100644 --- a/tests/inputs/literals.moon +++ b/tests/inputs/literals.moon @@ -11,6 +11,10 @@ 0xabcdef 0xABCDEF +.2323 +.2323e-1 +.2323e13434 + [[ hello world ]] [=[ hello world ]=] diff --git a/tests/outputs/literals.lua b/tests/outputs/literals.lua index 69609c5a..93c06293 100644 --- a/tests/outputs/literals.lua +++ b/tests/outputs/literals.lua @@ -7,6 +7,9 @@ _ = 0x12323 _ = 0xfF2323 _ = 0xabcdef _ = 0xABCDEF +_ = .2323 +_ = .2323e-1 +_ = .2323e13434 _ = [[ hello world ]] _ = [=[ hello world ]=] _ = [====[ hello world ]====] From 9629f69d16003bc090df9ef4d65605ae39b2cd94 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 24 Jan 2013 17:15:20 -0800 Subject: [PATCH 081/554] more documentation --- docs/reference.md | 45 +++++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/docs/reference.md b/docs/reference.md index 830aa982..67a8ddfa 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -537,7 +537,7 @@ single line: 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`. +array table. Doubling every even number: @@ -549,13 +549,8 @@ Doubling every even number: i ``` -Filtering out odd numbers: - - ```moon - my_numbers = {1,2,3,4,5,6} - odds = for x in *my_numbers - if x % 2 == 1 then x - ``` +You can also filter values by combining the for loop expression with the +[`continue`](#continue) statement. 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 @@ -1369,6 +1364,26 @@ extract by mixing the syntax: {:mix, :max, random: rand } = math ``` +### Destructuring In Other Places + +Destructuring can also show up in places where an assignment implicitly takes +place. An example of this is a `for` loop: + + + ```moon + tuples = { + {"hello", "world"} + {"egg", "head"} + } + + for {left, right} in *tuples + print left, right + ``` + +We know each element in the array table is a two item tuple, so we can unpack +it directly in the names clause of the for statement using a destructure. + + ## Function Stubs It is common to pass a function from an object around as a value, for example, @@ -1497,7 +1512,7 @@ way to do this: Upon installing MoonScript, a `moonscript` module is made available. The best use of this module is making your Lua's require function MoonScript aware. - ```moon + ```lua require "moonscript" ``` @@ -1522,7 +1537,6 @@ built in `load` function, which is run as the module. ### Load Functions - MoonScript provides `moonscript.load`, `moonscript.loadfile`, `mooonscript.loadstring`, which are analogous to Lua's `load`, `loadfile`, and `loadstring`. @@ -1532,7 +1546,8 @@ with MoonScript code instead of Lua Code. ```moononly - require "moonscript" + moonscript = require "moonscript" + fn = moonscript.loadstring 'print "hi!"' fn! ``` @@ -1543,7 +1558,7 @@ makes it so the file does not implicitly return its last statement. ```moononly - require "moonscript" + moonscript = require "moonscript" fn = moonscript.loadstring "10" print fn! -- prints "10" @@ -1594,10 +1609,8 @@ Here is a quick example of how you would compile a MoonScript string to a Lua String: ```moononly - require "moonscript.parse" - require "moonscript.compile" - - import parse, compile from moonscript + parse = require "moonscript.parse" + compile = require "moonscript.compile" moon_code = [[(-> print "hello world")!]] From 7c4cd41fbac3ee1088c9fcb7fbe6fa70e3764ab2 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 24 Jan 2013 17:17:03 -0800 Subject: [PATCH 082/554] version bump --- docs/reference.md | 2 +- docs/standard_lib.md | 2 +- moonscript/version.lua | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/reference.md b/docs/reference.md index 67a8ddfa..e664dba7 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -1,6 +1,6 @@ target: reference/index template: reference - title: MoonScript v0.2.2 - Language Guide + title: MoonScript v0.2.3 - Language Guide short_name: lang -- MoonScript is a programming language that compiles to diff --git a/docs/standard_lib.md b/docs/standard_lib.md index 3aeeee3d..546a9569 100644 --- a/docs/standard_lib.md +++ b/docs/standard_lib.md @@ -1,6 +1,6 @@ target: reference/standard_lib template: reference - title: MoonScript v0.2.2 - Standard Library + title: MoonScript v0.2.3 - Standard Library short_name: stdlib -- diff --git a/moonscript/version.lua b/moonscript/version.lua index 7347ffda..6c494d59 100644 --- a/moonscript/version.lua +++ b/moonscript/version.lua @@ -1,7 +1,7 @@ module("moonscript.version", package.seeall) -version = "0.2.2" +version = "0.2.3" function print_version() print("MoonScript version "..version) end From 05f6a0b7f7de5896bcacd278eb215e00c49d9160 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 24 Jan 2013 18:44:14 -0800 Subject: [PATCH 083/554] update switch docs --- docs/reference.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/reference.md b/docs/reference.md index e664dba7..64d89da0 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -696,12 +696,15 @@ is done with the `==` operator. switch name when "Robert" print "You are robert" - when "Dan" + when "Dan", "Daniel" print "Your name, it's Dan" else print "I don't know about your name" ``` +A switch `when` clause can match against multiple values by listing them out +comma separated. + Switches can be used as expressions as well, here we can assign the result of the switch to a variable: From cb8cd1f186e6c62fa6fcefb2b1db6b002843c0ce Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 29 Jan 2013 00:43:02 -0800 Subject: [PATCH 084/554] fix broken moonloader #71 --- moonscript/init.lua | 17 ++++++----------- moonscript/init.moon | 6 ++++-- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/moonscript/init.lua b/moonscript/init.lua index 3474a925..7612c56a 100644 --- a/moonscript/init.lua +++ b/moonscript/init.lua @@ -7,11 +7,12 @@ do split, dump, get_options, unpack = _table_0.split, _table_0.dump, _table_0.get_options, _table_0.unpack end local lua = { - loadstring = loadstring + loadstring = loadstring, + load = load } -local dirsep = "/" -local line_tables = require("moonscript.line_tables") -local create_moonpath +local dirsep, line_tables, create_moonpath, to_lua, moon_loader, init_loader, loadstring, loadfile, dofile +dirsep = "/" +line_tables = require("moonscript.line_tables") create_moonpath = function(package_path) local paths = split(package_path, ";") for i, path in ipairs(paths) do @@ -22,7 +23,6 @@ create_moonpath = function(package_path) end return concat(paths, ";") end -local to_lua to_lua = function(text, options) if options == nil then options = { } @@ -41,10 +41,9 @@ to_lua = function(text, options) end return code, ltable end -local moon_loader moon_loader = function(name) local name_path = name:gsub("%.", dirsep) - local file, file_path = nil, nil + local file, file_path local _list_0 = split(package.moonpath, ";") for _index_0 = 1, #_list_0 do local path = _list_0[_index_0] @@ -65,14 +64,12 @@ end if not package.moonpath then package.moonpath = create_moonpath(package.path) end -local init_loader init_loader = function() return insert(package.loaders or package.searchers, 2, moon_loader) end if not (_G.moon_no_loader) then init_loader() end -local loadstring loadstring = function(...) local options, str, chunk_name, mode, env = get_options(...) chunk_name = chunk_name or "=(moonscript.loadstring)" @@ -90,7 +87,6 @@ loadstring = function(...) env })) end -local loadfile loadfile = function(fname, ...) local file, err = io.open(fname) if not file then @@ -100,7 +96,6 @@ loadfile = function(fname, ...) file:close() return loadstring(text, fname, ...) end -local dofile dofile = function(...) local f = assert(loadfile(...)) return f() diff --git a/moonscript/init.moon b/moonscript/init.moon index cb97d1db..aa7d2edf 100644 --- a/moonscript/init.moon +++ b/moonscript/init.moon @@ -5,7 +5,9 @@ parse = require "moonscript.parse" import concat, insert from table import split, dump, get_options, unpack from require "moonscript.util" -lua = :loadstring +lua = :loadstring, :load + +local * dirsep = "/" line_tables = require "moonscript.line_tables" @@ -36,7 +38,7 @@ to_lua = (text, options={}) -> moon_loader = (name) -> name_path = name\gsub "%.", dirsep - file, file_path = nil, nil + local file, file_path for path in *split package.moonpath, ";" file_path = path\gsub "?", name_path file = io.open file_path From 5ec921484b77f5a03efc3b4d7d05a04413397efd Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 29 Jan 2013 00:46:18 -0800 Subject: [PATCH 085/554] bump version --- moonscript/version.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/moonscript/version.lua b/moonscript/version.lua index 6c494d59..e9595d0c 100644 --- a/moonscript/version.lua +++ b/moonscript/version.lua @@ -1,7 +1,7 @@ module("moonscript.version", package.seeall) -version = "0.2.3" +version = "0.2.3-2" function print_version() print("MoonScript version "..version) end From 72ceaae73b9d178710369a3af472442ef6756ead Mon Sep 17 00:00:00 2001 From: Robert Gieseke Date: Sat, 2 Feb 2013 20:09:43 +0100 Subject: [PATCH 086/554] Scintillua: Update lexer for Lua 5.2 --- extra/scintillua/lexers/moonscript.lua | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/extra/scintillua/lexers/moonscript.lua b/extra/scintillua/lexers/moonscript.lua index 72cb66af..7a9e54b8 100644 --- a/extra/scintillua/lexers/moonscript.lua +++ b/extra/scintillua/lexers/moonscript.lua @@ -3,9 +3,9 @@ local l = lexer local token, word_match = l.token, l.word_match -local P, S, R = l.lpeg.P, l.lpeg.S, l.lpeg.R +local P, S, R = lpeg.P, lpeg.S, lpeg.R -module(...) +local M = { _NAME = 'moonscript' } -- Whitespace. local ws = token(l.WHITESPACE, l.space^1) @@ -41,7 +41,7 @@ local keyword = token(l.KEYWORD, word_match { 'using', 'switch', 'when', }) -local special = token("special", word_match { "true", "false", "nil" }) +local special = token("special", word_match { "true", "false", "nil" }) -- Functions. local builtin = token(l.FUNCTION, word_match({ @@ -92,7 +92,7 @@ local proper_ident = token("proper_ident", R("AZ") * l.word) local tbl_key = token("tbl_key", l.word * ":" + ":" * l.word ) -_rules = { +M._rules = { { 'whitespace', ws }, { 'error', err }, { 'self', self_var }, @@ -112,7 +112,7 @@ _rules = { local style_special = { fore = l.colors.light_blue } local style_fndef = { fore = l.colors.green } -_tokenstyles = { +M._tokenstyles = { { 'self_ref', style_special }, { 'proper_ident', l.style_class }, { 'fndef', style_fndef }, @@ -120,3 +120,5 @@ _tokenstyles = { { 'special', style_special }, { 'tbl_key', { fore = l.colors.red } }, } + +return M From ca2dd78a217d0ba2082e5614009edca7d5f23f6b Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 5 Feb 2013 08:45:00 -0800 Subject: [PATCH 087/554] move position of original line number in rewritten stack trace, fixes #75 --- moonscript/errors.lua | 4 ++-- moonscript/errors.moon | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/moonscript/errors.lua b/moonscript/errors.lua index 85266cf6..58d1d9c1 100644 --- a/moonscript/errors.lua +++ b/moonscript/errors.lua @@ -80,10 +80,10 @@ rewrite_traceback = function(text, err) fname, ":", reverse_line_number(fname, tbl, line, cache), + ": ", "(", line, - ")", - ": ", + ") ", msg }) else diff --git a/moonscript/errors.moon b/moonscript/errors.moon index c74f69df..3bba4476 100644 --- a/moonscript/errors.moon +++ b/moonscript/errors.moon @@ -62,8 +62,9 @@ rewrite_traceback = (text, err) -> concat { fname, ":" reverse_line_number(fname, tbl, line, cache) - "(", line, ")" - ": ", msg + ": " + "(", line, ") " + msg } else trace From 610d3d5690002d520dd2bd6b17addcf3996f58b7 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 27 Feb 2013 19:17:16 -0800 Subject: [PATCH 088/554] return style requires, fix #88 --- bin/moonc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/moonc b/bin/moonc index d99f228f..d7a92206 100755 --- a/bin/moonc +++ b/bin/moonc @@ -6,8 +6,8 @@ local util = require "moonscript.util" local dump_tree = require"moonscript.dump".tree -require "alt_getopt" -require "lfs" +local alt_getopt = require "alt_getopt" +local lfs = require "lfs" local opts, ind = alt_getopt.get_opts(arg, "vhwt:pTXb", { print = "p", tree = "T", version = "v", help = "h" From 539ae2850fe598e20fa1c0b6339b64e88e112ef2 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 19 Mar 2013 09:11:16 -0700 Subject: [PATCH 089/554] add moonscript.base module for loading moonscrit without installing moonloader --- moonscript-dev-1.rockspec | 1 + moonscript/base.lua | 2 ++ moonscript/base.moon | 2 ++ 3 files changed, 5 insertions(+) create mode 100644 moonscript/base.lua create mode 100644 moonscript/base.moon diff --git a/moonscript-dev-1.rockspec b/moonscript-dev-1.rockspec index 9906efc8..457c0169 100644 --- a/moonscript-dev-1.rockspec +++ b/moonscript-dev-1.rockspec @@ -25,6 +25,7 @@ build = { ["moon"] = "moon/init.lua", ["moon.all"] = "moon/all.lua", ["moonscript"] = "moonscript/init.lua", + ["moonscript.base"] = "moonscript/base.lua", ["moonscript.compile"] = "moonscript/compile.lua", ["moonscript.compile.statement"] = "moonscript/compile/statement.lua", ["moonscript.compile.value"] = "moonscript/compile/value.lua", diff --git a/moonscript/base.lua b/moonscript/base.lua new file mode 100644 index 00000000..2636187f --- /dev/null +++ b/moonscript/base.lua @@ -0,0 +1,2 @@ +_G.moon_no_loader = true +return require("moonscript") diff --git a/moonscript/base.moon b/moonscript/base.moon new file mode 100644 index 00000000..b5fae84f --- /dev/null +++ b/moonscript/base.moon @@ -0,0 +1,2 @@ +_G.moon_no_loader = true +require "moonscript" From cdd413a2a82bc01adc0cd75f8ff4ca47bab701df Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 19 Mar 2013 09:22:27 -0700 Subject: [PATCH 090/554] load* functions return nil and error instead of throwing error fixes #87 --- moonscript/init.lua | 18 ++++++++---------- moonscript/init.moon | 16 ++++++++-------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/moonscript/init.lua b/moonscript/init.lua index 7612c56a..2488d6d9 100644 --- a/moonscript/init.lua +++ b/moonscript/init.lua @@ -29,15 +29,15 @@ to_lua = function(text, options) end if "string" ~= type(text) then local t = type(text) - error("expecting string (got " .. t .. ")", 2) + return nil, "expecting string (got " .. t .. ")", 2 end local tree, err = parse.string(text) if not tree then - error(err, 2) + return nil, err end local code, ltable, pos = compile.tree(tree, options) if not code then - error(compile.format_error(ltable, pos, text), 2) + return nil, compile.format_error(ltable, pos, text), 2 end return code, ltable end @@ -73,14 +73,12 @@ end loadstring = function(...) local options, str, chunk_name, mode, env = get_options(...) chunk_name = chunk_name or "=(moonscript.loadstring)" - local passed, code, ltable = pcall(function() - return to_lua(str, options) - end) - if not passed then - error(chunk_name .. ": " .. code, 2) + local code, ltable_or_err = to_lua(str, options) + if not (code) then + return nil, ltable_or_err end if chunk_name then - line_tables[chunk_name] = ltable + line_tables[chunk_name] = ltable_or_err end return (lua.loadstring or lua.load)(code, chunk_name, unpack({ mode, @@ -89,7 +87,7 @@ loadstring = function(...) end loadfile = function(fname, ...) local file, err = io.open(fname) - if not file then + if not (file) then return nil, err end local text = assert(file:read("*a")) diff --git a/moonscript/init.moon b/moonscript/init.moon index aa7d2edf..2c9fe413 100644 --- a/moonscript/init.moon +++ b/moonscript/init.moon @@ -23,15 +23,15 @@ create_moonpath = (package_path) -> to_lua = (text, options={}) -> if "string" != type text t = type text - error "expecting string (got ".. t ..")", 2 + return nil, "expecting string (got ".. t ..")", 2 tree, err = parse.string text if not tree - error err, 2 + return nil, err code, ltable, pos = compile.tree tree, options if not code - error compile.format_error(ltable, pos, text), 2 + return nil, compile.format_error(ltable, pos, text), 2 code, ltable @@ -63,17 +63,17 @@ loadstring = (...) -> options, str, chunk_name, mode, env = get_options ... chunk_name or= "=(moonscript.loadstring)" - passed, code, ltable = pcall -> to_lua str, options - if not passed - error chunk_name .. ": " .. code, 2 + code, ltable_or_err = to_lua str, options + unless code + return nil, ltable_or_err - line_tables[chunk_name] = ltable if chunk_name + line_tables[chunk_name] = ltable_or_err if chunk_name -- the unpack prevents us from passing nil (lua.loadstring or lua.load) code, chunk_name, unpack { mode, env } loadfile = (fname, ...) -> file, err = io.open fname - return nil, err if not file + return nil, err unless file text = assert file\read "*a" file\close! loadstring text, fname, ... From 499afbaefead8168dd23429bafd90da42eaf147f Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 19 Mar 2013 09:53:25 -0700 Subject: [PATCH 091/554] make testing work with latest version of busted --- Makefile | 2 +- test2.moon | 50 +++++++++++++++++++++----------------------------- 2 files changed, 22 insertions(+), 30 deletions(-) diff --git a/Makefile b/Makefile index 20b1b607..d90631dd 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ test:: - TIME=1 lua5.1 bin/moon test2.moon + moonc test2.moon && TIME=1 busted test2.lua local: luarocks make --local moonscript-dev-1.rockspec diff --git a/test2.moon b/test2.moon index 516c3071..49eec864 100644 --- a/test2.moon +++ b/test2.moon @@ -1,6 +1,5 @@ -require "lfs" -require "busted" +lfs = require "lfs" parse = require "moonscript.parse" compile = require "moonscript.compile" @@ -118,31 +117,24 @@ describe "input tests", -> nil -busted.options = { - output: require'busted.output.utf_terminal'! - suppress_pending: true -} - -print busted! - -if options.show_timings - format_time = (sec) -> ("%.3fms")\format(sec*1000) - col_width = math.max unpack [#t[1] for t in *timings] - - print "\nTimings:" - total_parse, total_compile = 0, 0 - for tuple in *timings - name, parse_time, compile_time = unpack tuple - name = name .. (" ")\rep col_width - #name - total_parse += parse_time - total_compile += compile_time - - print " * " .. name, - "p: " .. format_time(parse_time), - "c: " .. format_time(compile_time) - - print "\nTotal:" - print " parse:", format_time total_parse - print " compile:", format_time total_compile - + if options.show_timings + teardown -> + format_time = (sec) -> ("%.3fms")\format(sec*1000) + col_width = math.max unpack [#t[1] for t in *timings] + + print "\nTimings:" + total_parse, total_compile = 0, 0 + for tuple in *timings + name, parse_time, compile_time = unpack tuple + name = name .. (" ")\rep col_width - #name + total_parse += parse_time + total_compile += compile_time + + print " * " .. name, + "p: " .. format_time(parse_time), + "c: " .. format_time(compile_time) + + print "\nTotal:" + print " parse:", format_time total_parse + print " compile:", format_time total_compile From 4b5d6f1cdee8a8fed69ad3b5af75b6d07fd34c99 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 16 Apr 2013 11:16:47 -0700 Subject: [PATCH 092/554] a-b is no longer a function call #96 --- docs/reference.md | 12 +++++------- moonscript/parse.lua | 2 +- tests/inputs/syntax.moon | 8 ++++++++ tests/outputs/syntax.lua | 6 +++++- 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/docs/reference.md b/docs/reference.md index 64d89da0..bbb7cd67 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -188,20 +188,18 @@ restrictions must be put in place to avoid parsing ambiguity involving whitespace. The minus sign plays two roles, a unary negation operator and a binary -subtraction operator. In order to force subtraction a space must be placed -after the `-` operator. In order to force a negation, no space must follow -the `-`. Consider the examples below. +subtraction operator. Consider how the following examples compile: ```moon a = x - 10 b = x-10 c = x -y + d = x- z ``` -The precedence of the first argument of a function call can also be controlled -using whitespace if the argument is a literal string. In Lua, it is common to -leave off parentheses when calling a function with a single string or table -literal. +The precedence of the first argument of a function call can be controlled using +whitespace if the argument is a literal string. In Lua, it is common to leave +off parentheses when calling a function with a single string or table literal. When there is no space between a variable and a string literal, the function call takes precedence over any following expressions. No other diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 37f15b7b..f6d04c2c 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -597,7 +597,7 @@ local build_grammar = wrap_env(function() ExpList = Exp * (sym"," * Exp)^0, ExpListLow = Exp * ((sym"," + sym";") * Exp)^0, - InvokeArgs = ExpList * (sym"," * (TableBlock + SpaceBreak * Advance * ArgBlock * TableBlock^-1) + TableBlock)^-1 + TableBlock, + InvokeArgs = -P"-" * (ExpList * (sym"," * (TableBlock + SpaceBreak * Advance * ArgBlock * TableBlock^-1) + TableBlock)^-1 + TableBlock), ArgBlock = ArgLine * (sym"," * SpaceBreak * ArgLine)^0 * PopIndent, ArgLine = CheckIndent * ExpList } diff --git a/tests/inputs/syntax.moon b/tests/inputs/syntax.moon index 6e3a09bf..09a5dabd 100644 --- a/tests/inputs/syntax.moon +++ b/tests/inputs/syntax.moon @@ -243,4 +243,12 @@ x.while.true = "hello" x or= "hello" x and= "hello" +-- + +z = a-b +z = a -b +z = a - b +z = a- b + + -- cooool diff --git a/tests/outputs/syntax.lua b/tests/outputs/syntax.lua index 893787af..72d3dab6 100644 --- a/tests/outputs/syntax.lua +++ b/tests/outputs/syntax.lua @@ -237,4 +237,8 @@ a = a / func("cool") x["then"] = "hello" x["while"]["true"] = "hello" x = x or "hello" -x = x and "hello" \ No newline at end of file +x = x and "hello" +z = a - b +z = a(-b) +z = a - b +z = a - b \ No newline at end of file From c61b826f3b38c4e54d00a38a830bb7f83253dd0a Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 17 Apr 2013 21:05:01 -0700 Subject: [PATCH 093/554] remove unneeded indentation from documentation --- docs/reference.md | 1371 +++++++++++++++++++++--------------------- docs/standard_lib.md | 135 ++--- 2 files changed, 754 insertions(+), 752 deletions(-) diff --git a/docs/reference.md b/docs/reference.md index bbb7cd67..1f357bbd 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -24,11 +24,11 @@ Assigning to an undeclared name will cause it to be declared as a new local variable. The language is dynamically typed so you can assign any value to any variable. You can assign multiple names and values at once just like Lua: - ```moon - hello = "world" - a,b,c = 1, 2, 3 - hello = 123 -- uses the existing variable - ``` +```moon +hello = "world" +a,b,c = 1, 2, 3 +hello = 123 -- uses the existing variable +``` If you wish to create a global variable it must be done using the [`export`](#export_statement) keyword. @@ -42,25 +42,25 @@ variable, or shadow an existing one. for updating and assigning at the same time. They are aliases for their expanded equivalents. - ```moon - x = 0 - x += 10 +```moon +x = 0 +x += 10 - s = "hello " - s ..= "world" +s = "hello " +s ..= "world" - b = false - b and= true or false - ``` +b = false +b and= true or false +``` ## Comments Like Lua, comments start with `--` and continue to the end of the line. Comments are not written to the output. - ```moon - -- I am a comment - ``` +```moon +-- I am a comment +``` ## Literals & Operators @@ -75,80 +75,80 @@ MoonScript also supports all the same binary and unary operators. Additionally All functions are created using a function expression. A simple function is denoted using the arrow: `->` - ```moon - my_function = -> - my_function() -- call the empty function - ``` +```moon +my_function = -> +my_function() -- call the empty function +``` The body of the function can either be one statement placed directly after the arrow, or it can be a series of statements indented on the following lines: - ```moon - func_a = -> print "hello world" +```moon +func_a = -> print "hello world" - func_b = -> - value = 100 - print "The value:", value - ``` +func_b = -> + value = 100 + print "The value:", value +``` If a function has no arguments, it can be called using the `!` operator, instead of empty parentheses. The `!` invocation is the preferred way to call functions with no arguments. - ```moon - func_a! - func_b() - ``` +```moon +func_a! +func_b() +``` Functions with arguments can be created by preceding the arrow with a list of argument names in parentheses: - ```moon - sum = (x, y) -> print "sum", x + y - ``` +```moon +sum = (x, y) -> print "sum", x + y +``` Functions can be called by listing the arguments after the name of an expresion that evaluates to a function. When chaining together function calls, the arguments are applied to the closest function to the left. - ```moon - sum 10, 20 - print sum 10, 20 +```moon +sum 10, 20 +print sum 10, 20 - a b c "a", "b", "c" - ``` +a b c "a", "b", "c" +``` In order to avoid ambiguity in when calling functions, parentheses can also be used to surround the arguments. This is required here in order to make sure the right arguments get sent to the right functions. - ```moon - print "x:", sum(10, 20), "y:", sum(30, 40) - ``` +```moon +print "x:", sum(10, 20), "y:", sum(30, 40) +``` There must not be any space between the opening parenthesis and the function. Functions will coerce the last statement in their body into a return statement, this is called implicit return: - ```moon - sum = (x, y) -> x + y - print "The sum is ", sum 10, 20 - ``` +```moon +sum = (x, y) -> x + y +print "The sum is ", sum 10, 20 +``` And if you need to explicitly return, you can use the `return` keyword: - ```moon - sum = (x, y) -> return x + y - ``` +```moon +sum = (x, y) -> return x + y +``` Just like in Lua, functions can return multiple values. The last statement must be a list of values separated by commas: - ```moon - mystery = (x, y) -> x + y, x - y - a,b = mystery 10, 20 - ``` +```moon +mystery = (x, y) -> x + y, x - y +a,b = mystery 10, 20 +``` ### Fat Arrows @@ -156,9 +156,9 @@ Because it is an idiom in Lua to send an object as the first argument when calling a method, a special syntax is provided for creating functions which automatically includes a `self` argument. - ```moon - func = (num) => @value + num - ``` +```moon +func = (num) => @value + num +``` ### Argument Defaults @@ -166,20 +166,20 @@ It is possible to provide default values for the arguments of a function. An argument is determined to be empty if its value is `nil`. Any `nil` arguments that have a default value will be replace before the body of the function is run. - ```moon - my_function = (name="something", height=100) -> - print "Hello I am", name - print "My height is", height - ``` +```moon +my_function = (name="something", height=100) -> + print "Hello I am", name + print "My height is", height +``` An argument default value expression is evaluated in the body of the function in the order of the argument declarations. For this reason default values have access to previously declared arguments. - ```moon - some_args = (x=100, y=x+1000) -> - print x + y - ``` +```moon +some_args = (x=100, y=x+1000) -> + print x + y +``` ### Considerations @@ -190,12 +190,12 @@ whitespace. The minus sign plays two roles, a unary negation operator and a binary subtraction operator. Consider how the following examples compile: - ```moon - a = x - 10 - b = x-10 - c = x -y - d = x- z - ``` +```moon +a = x - 10 +b = x-10 +c = x -y +d = x- z +``` The precedence of the first argument of a function call can be controlled using whitespace if the argument is a literal string. In Lua, it is common to leave @@ -209,10 +209,10 @@ Where there is a space following a variable and a string literal, the function call acts as show above. The string literal belongs to any following expressions (if they exist), which serves as the argument list. - ```moon - x = func"hello" + 100 - y = func "hello" + 100 - ``` +```moon +x = func"hello" + 100 +y = func "hello" + 100 +``` ### Multi-line arguments @@ -226,147 +226,147 @@ must end in a comma. And the following line must be indented more than the current indentation. Once indented, all other argument lines must be at the same level of indentation to be part of the argument list - ```moon - my_func 5,4,3, - 8,9,10 +```moon +my_func 5,4,3, + 8,9,10 - cool_func 1,2, - 3,4, - 5,6, - 7,8 - ``` +cool_func 1,2, + 3,4, + 5,6, + 7,8 +``` This type of invocation can be nested. The level of indentation is used to determine to which function the arguments belong to. - ```moon - my_func 5,6,7, - 6, another_func 6,7,8, - 9,1,2, - 5,4 - ``` +```moon +my_func 5,6,7, + 6, another_func 6,7,8, + 9,1,2, + 5,4 +``` Because [tables](#table_literals) also use the comma as a delimiter, this indentation syntax is helpful for letting values be part of the argument list instead of being part of the table. - ```moon - x = { - 1,2,3,4, a_func 4,5, - 5,6, - 8,9,10 - } - ``` +```moon +x = { + 1,2,3,4, a_func 4,5, + 5,6, + 8,9,10 +} +``` Although uncommon, notice how we can give a deeper indentation for function arguments if we know we will be using a lower indentation further on. - ```moon - y = { my_func 1,2,3, - 4,5, - 5,6,7 - } - ``` +```moon +y = { my_func 1,2,3, + 4,5, + 5,6,7 +} +``` The same thing can be done with other block level statements like [conditionals](#conditionals). We can use indentation level to determine what statement a value belongs to: - ```moon - if func 1,2,3, - "hello", - "world" - print "hello" - print "I am inside if" +```moon +if func 1,2,3, + "hello", + "world" + print "hello" + print "I am inside if" - if func 1,2,3, - "hello", - "world" - print "hello" - print "I am inside if" - ``` +if func 1,2,3, + "hello", + "world" + print "hello" + print "I am inside if" +``` ## Table Literals Like in Lua, tables are delimited in curly braces. - ```moon - some_values = { 1, 2, 3, 4 } - ``` +```moon +some_values = { 1, 2, 3, 4 } +``` Unlike Lua, assigning a value to a key in a table is done with `:` (instead of `=`). - ```moon - some_values = { - name: "Bill", - age: 200, - ["favorite food"]: "rice" - } - ``` +```moon +some_values = { + name: "Bill", + age: 200, + ["favorite food"]: "rice" +} +``` The curly braces can be left off if a single table of key value pairs is being assigned. - ```moon - profile = - height: "4 feet", - shoe_size: 13, - favorite_foods: {"ice cream", "donuts"} - ``` +```moon +profile = + height: "4 feet", + shoe_size: 13, + favorite_foods: {"ice cream", "donuts"} +``` Newlines can be used to delimit values instead of a comma (or both): - ```moon - values = { - 1,2,3,4 - 5,6,7,8 - name: "superman" - occupation: "crime fighting" - } - ``` +```moon +values = { + 1,2,3,4 + 5,6,7,8 + name: "superman" + occupation: "crime fighting" +} +``` When creating a single line table literal, the curly braces can also be left off: - ```moon - my_function dance: "Tango", partner: "none" +```moon +my_function dance: "Tango", partner: "none" - y = type: "dog", legs: 4, tails: 1 - ``` +y = type: "dog", legs: 4, tails: 1 +``` The keys of a table literal can be language keywords without being escaped: - ```moon - tbl = { - do: "something" - end: "hunger" - } - ``` +```moon +tbl = { + do: "something" + end: "hunger" +} +``` If you are constructing a table out of variables and wish the keys to be the same as the variable names, then the `:` prefix operator can be used: - ```moon - hair = "golden" - height = 200 - person = { :hair, :height, shoe_size: 40 } +```moon +hair = "golden" +height = 200 +person = { :hair, :height, shoe_size: 40 } - print_table :hair, :height - ``` +print_table :hair, :height +``` If you want the key of a field in the table to to be result of an expression, then you can wrap it in `[` `]`, just like in Lua. You can also use a string literal directly as a key, leaving out the square brackets. This is useful if your key has any special characters. - ```moon - t = { - [1 + 2]: "hello" - "hello world": true - } +```moon +t = { + [1 + 2]: "hello" + "hello world": true +} - ``` +``` ## Comprehensions @@ -382,42 +382,42 @@ the key and the value on each iteration. The following creates a copy of the `items` table but with all the values doubled. - ```moon - items = { 1, 2, 3, 4 } - doubled = [item * 2 for i, item in ipairs items] - ``` +```moon +items = { 1, 2, 3, 4 } +doubled = [item * 2 for i, item in ipairs items] +``` The items included in the new table can be restricted with a `when` clause: - ```moon - iter = ipairs items - slice = [item for i, item in iter when i > 1 and i < 3] - ``` +```moon +iter = ipairs items +slice = [item for i, item in iter when i > 1 and i < 3] +``` Because it is common to iterate over the values of a numerically indexed table, an `*` operator is introduced. The doubled example can be rewritten as: - ```moon - doubled = [item * 2 for item in *items] - ``` +```moon +doubled = [item * 2 for item in *items] +``` The `for` and `when` clauses can be chained as much as desired. The only requirement is that a comprehension has at least one `for` clause. Using multiple `for` clauses is the same as using nested loops: - ```moon - x_coords = {4, 5, 6, 7} - y_coords = {9, 2, 3} +```moon +x_coords = {4, 5, 6, 7} +y_coords = {9, 2, 3} - points = [{x,y} for x in *x_coords for y in *y_coords] - ``` +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] - ``` +```moon +evens = [i for i=1,100 when i % 2 == 0] +``` ### Table Comprehensions @@ -426,31 +426,31 @@ The syntax for table comprehensions is very similar, only differing by using `{` This example makes a copy of the table`thing`: - ```moon - thing = { - color: "red" - name: "fast" - width: 123 - } +```moon +thing = { + color: "red" + name: "fast" + width: 123 +} - thing_copy = {k,v for k,v in pairs thing} - ``` +thing_copy = {k,v for k,v in pairs thing} +``` Table comprehensions, like list comprehensions, also support multiple `for` and `when` clauses. In this example we use a `when` clause to prevent the value associated with the `color` key from being copied. - ```moon - no_color = {k,v for k,v in pairs thing when k != "color"} - ``` +```moon +no_color = {k,v for k,v in pairs thing when k != "color"} +``` The `*` operator is also supported. Here we create a square root look up table for a few numbers. - ```moon - numbers = {1,2,3,4} - sqrts = {i, math.sqrt i for i in *numbers} - ``` +```moon +numbers = {1,2,3,4} +sqrts = {i, math.sqrt i for i in *numbers} +``` The key-value tuple in a table comprehension can also come from a single expression, in which case the expression should return two values. The @@ -459,10 +459,10 @@ first is used as the key and the second is used as the value: In this example we convert an array of pairs to a table where the first item in the pair is the key and the second is the value. - ```moon - tuples = {{"hello", "world"}, {"foo", "bar"}} - tbl = {unpack tuple for tuple in *tuples} - ``` +```moon +tuples = {{"hello", "world"}, {"foo", "bar"}} +tbl = {unpack tuple for tuple in *tuples} +``` ### Slicing @@ -473,65 +473,65 @@ a step size in a `for` loop. Here we can set the minimum and maximum bounds, taking all items with indexes between 1 and 5 inclusive: - ```moon - slice = [item for item in *items[1,5]] - ``` +```moon +slice = [item for item in *items[1,5]] +``` Any of the slice arguments can be left off to use a sensible default. In this example, if the max index is left off it defaults to the length of the table. This will take everything but the first element: - ```moon - slice = [item for item in *items[2,]] - ``` +```moon +slice = [item for item in *items[2,]] +``` If the minimum bound is left out, it defaults to 1. Here we only provide a step size and leave the other bounds blank. This takes all odd indexed items: (1, 3, 5, ...) - ```moon - slice = [item for item in *items[,,2]] - ``` +```moon +slice = [item for item in *items[,,2]] +``` ## String Interpolation You can mix expressions into string literals using `#{}` syntax. - ```moon - print "I am #{math.random! * 100}% sure." - ``` +```moon +print "I am #{math.random! * 100}% sure." +``` String interpolation is only available in double quoted strings. ## For Loop There are two for loop forms, just like in Lua. A numeric one and a generic one: - ```moon - for i = 10, 20 - print i +```moon +for i = 10, 20 + print i - for k = 1,15,2 -- an optional step provided - print k +for k = 1,15,2 -- an optional step provided + print k - for key, value in pairs object - print key, value - ``` +for key, value in pairs object + print key, value +``` The slicing and `*` operators can be used, just like with comprehensions: - ```moon - for item in *items[2,4] - print item - ``` +```moon +for item in *items[2,4] + print item +``` A shorter syntax is also available for all variations when the body is only a single line: - ```moon - for item in *items do print item +```moon +for item in *items do print item - for j = 1,10,3 do print j - ``` +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 @@ -539,13 +539,13 @@ array table. Doubling every even number: - ```moon - doubled_evens = for i=1,20 - if i % 2 == 0 - i * 2 - else - i - ``` +```moon +doubled_evens = for i=1,20 + if i % 2 == 0 + i * 2 + else + i +``` You can also filter values by combining the for loop expression with the [`continue`](#continue) statement. @@ -555,13 +555,13 @@ 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. - ```moon - func_a = -> for i=1,10 do i - func_b = -> return for i=1,10 do i +```moon +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 - ``` +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. @@ -570,14 +570,14 @@ need to return the results of the loop. The while loop also comes in two variations: - ```moon - i = 10 - while i > 0 - print i - i -= 1 +```moon +i = 10 +while i > 0 + print i + i -= 1 - while running == true do my_function! - ``` +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 accumulated value of a while loop, the statement @@ -587,63 +587,63 @@ must be explicitly returned. A `continue` statement can be used to skip the current iteration in a loop. - ```moon - i = 0 - while i < 10 - continue if i % 2 ==0 - print i - ``` +```moon +i = 0 +while i < 10 + continue if i % 2 ==0 + print i +``` `continue` can also be used with loop expressions to prevent that iteration from accumulating into the result. This examples filters the array table into just even numbers: - ```moon - my_numbers = {1,2,3,4,5,6} - odds = for x in *my_numbers - continue if x % 2 == 1 - x - ``` +```moon +my_numbers = {1,2,3,4,5,6} +odds = for x in *my_numbers + continue if x % 2 == 1 + x +``` ## Conditionals - ```moon - have_coins = false - if have_coins - print "Got coins" - else - print "No coins" - ``` +```moon +have_coins = false +if have_coins + print "Got coins" +else + print "No coins" +``` A short syntax for single statements can also be used: - ```moon - have_coins = false - if have_coins then print "Got coins" else print "No coins" - ``` +```moon +have_coins = false +if have_coins then print "Got coins" else print "No coins" +``` Because if statements can be used as expressions, this can able be written as: - ```moon - have_coins = false - print if have_coins then "Got coins" else "No coins" - ``` +```moon +have_coins = false +print if have_coins then "Got coins" else "No coins" +``` Conditionals can also be used in return statements and assignments: - ```moon - is_tall = (name) -> - if name == "Rob" - true - else - false +```moon +is_tall = (name) -> + if name == "Rob" + true + else + false - message = if is_tall "Rob" - "I am very tall" - else - "I am not so tall" +message = if is_tall "Rob" + "I am very tall" +else + "I am not so tall" - print message -- prints: I am very tall - ``` +print message -- prints: I am very tall +``` ### With Assignment @@ -653,34 +653,34 @@ the value that was assigned to will be used as the conditional expression. The assigned variable is only in scope for the body of the conditional, meaning it is never available if the value is not truthy. - ```moon - if user = database.find_user "moon" - print user.name - ``` +```moon +if user = database.find_user "moon" + print user.name +``` - ```moon - if hello = os.getenv "hello" - print "You have hello", hello - elseif world = os.getenv "world" - print "you have world", world - else - print "nothing :(" - ``` +```moon +if hello = os.getenv "hello" + print "You have hello", hello +elseif world = os.getenv "world" + print "you have world", world +else + print "nothing :(" +``` ## Line Decorators For convenience, the for loop and if statement can be applied to single statements at the end of the line: - ```moon - print "hello world" if name == "Rob" - ``` +```moon +print "hello world" if name == "Rob" +``` And with basic loops: - ```moon - print "item: ", item for item in *items - ``` +```moon +print "item: ", item for item in *items +``` ## Switch @@ -689,16 +689,16 @@ check against the same value. Note that the value is only evaluated once. Like if statements, switches can have an else block to handle no matches. Comparison is done with the `==` operator. - ```moon - name = "Dan" - switch name - when "Robert" - print "You are robert" - when "Dan", "Daniel" - print "Your name, it's Dan" - else - print "I don't know about your name" - ``` +```moon +name = "Dan" +switch name + when "Robert" + print "You are robert" + when "Dan", "Daniel" + print "Your name, it's Dan" + else + print "I don't know about your name" +``` A switch `when` clause can match against multiple values by listing them out comma separated. @@ -706,26 +706,26 @@ comma separated. Switches can be used as expressions as well, here we can assign the result of the switch to a variable: - ```moon - b = 1 - next_number = switch b - when 1 - 2 - when 2 - 3 - else - error "can't count that high!" - ``` +```moon +b = 1 +next_number = switch b + when 1 + 2 + when 2 + 3 + else + error "can't count that high!" +``` We can use the `then` keyword to write a switch's `when` block on a single line. No extra keyword is needed to write the else block on a single line. - ```moon - msg = switch math.random(1, 5) - when 1 then "you are lucky" - when 2 then "you are almost lucky" - else "not so lucky" - ``` +```moon +msg = switch math.random(1, 5) + when 1 then "you are lucky" + when 2 then "you are almost lucky" + else "not so lucky" +``` It is worth noting the order of the case comparison expression. The case's expression is on the left hand side. This can be useful if the case's @@ -740,17 +740,17 @@ code if you wish to know the implementation details. A simple class: - ```moon - class Inventory - new: => - @items = {} +```moon +class Inventory + new: => + @items = {} - add_item: (name) => - if @items[name] - @items[name] += 1 - else - @items[name] = 1 - ``` + add_item: (name) => + if @items[name] + @items[name] += 1 + else + @items[name] = 1 +``` A class is declared with a `class` statement followed by a table-like declaration where all of the methods and properties are listed. @@ -767,11 +767,11 @@ The `@` prefix on a variable name is shorthand for `self.`. `@items` becomes Creating an instance of the class is done by calling the name of the class as a function. - ```moon - inv = Inventory! - inv\add_item "t-shirt" - inv\add_item "pants" - ``` +```moon +inv = Inventory! +inv\add_item "t-shirt" +inv\add_item "pants" +``` Because the instance of the class needs to be sent to the methods when they are called, the \\ operator is used. @@ -782,43 +782,43 @@ functions, but for other types of objects, undesired results may occur. Consider the example below, the `clothes` property is shared amongst all instances, so modifications to it in one instance will show up in another: - ```moononly - class Person - clothes: {} - give_item: (name) => - table.insert @clothes, name +```moononly +class Person + clothes: {} + give_item: (name) => + table.insert @clothes, name - a = Person! - b = Person! +a = Person! +b = Person! - a\give_item "pants" - b\give_item "shirt" +a\give_item "pants" +b\give_item "shirt" - -- will print both pants and shirt - print item for item in *a.clothes - ``` +-- will print both pants and shirt +print item for item in *a.clothes +``` The proper way to avoid this problem is to create the mutable state of the object in the constructor: - ```moononly - class Person - new: => - @clothes = {} - ``` +```moononly +class Person + new: => + @clothes = {} +``` ### Inheritance The `extends` keyword can be used in a class declaration to inherit the properties and methods from another class. - ```moon - class BackPack extends Inventory - size: 10 - add_item: (name) => - if #@items > size then error "backpack is full" - super name - ``` +```moon +class BackPack extends Inventory + size: 10 + add_item: (name) => + if #@items > size then error "backpack is full" + super name +``` Here we extend our Inventory class, and limit the amount of items it can carry. @@ -832,14 +832,14 @@ by calling the method `__inherited` on the parent class if it exists. The function receives two arguments, the class that is being inherited and the child class. - ```moononly - class Shelf - @__inherited: (child) => - print @__name, "was inherited by", child.__name +```moononly +class Shelf + @__inherited: (child) => + print @__name, "was inherited by", child.__name - -- will print: Shelf was inherited by Cupboard - class Cupboard extends Shelf - ``` +-- will print: Shelf was inherited by Cupboard +class Cupboard extends Shelf +``` ### Super @@ -863,17 +863,17 @@ retrieve a function, the raw function is returned. A few examples of using `super` in different ways: - ```moon - class MyClass extends ParentClass - a_method: => - -- the following have the same effect: - super "hello", "world" - super\a_method "hello", "world" - super.a_method self, "hello", "world" +```moon +class MyClass extends ParentClass + a_method: => + -- the following have the same effect: + super "hello", "world" + super\a_method "hello", "world" + super.a_method self, "hello", "world" - -- super as a value is equal to the parent class: - assert super == ParentClass - ``` + -- super as a value is equal to the parent class: + assert super == ParentClass +``` `super` can also be used on left side of a [Function Stub](#function_stubs). The only major difference is that instead of the resulting function being bound @@ -886,12 +886,12 @@ special `__class` property. This property holds the class object. The class object is what we call to build a new instance. We can also index the class object to retrieve class methods and properties. - ```moon - b = BackPack! - assert b.__class == BackPack +```moon +b = BackPack! +assert b.__class == BackPack - print BackPack.size -- prints 10 - ``` +print BackPack.size -- prints 10 +``` ### Class Objects The class object is what we create when we use a `class` statement. The class @@ -917,9 +917,9 @@ The class object has a couple special properties: The name of the class as when it was declared is stored as a string in the `__name` field of the class object. - ```moon - print BackPack.__name -- prints Backpack - ``` +```moon +print BackPack.__name -- prints Backpack +``` The *base* object is stored in `__base`. We can modify this table to add functionality to instances that have already been created and ones that are yet @@ -933,39 +933,39 @@ If the class extends from anything, the parent class object is stored in We can create variables directly in the class object instead of in the *base* by using `@` in the front of the property name in a class declaration. - ```moononly - class Things - @some_func: => print "Hello from", @__name +```moononly +class Things + @some_func: => print "Hello from", @__name - Things\some_func! +Things\some_func! - -- class variables not visible in instances - assert Things().some_func == nil +-- class variables not visible in instances +assert Things().some_func == nil - ``` +``` In expressions, we can use `@@` to access a value that is stored in the `__class` of `self`. Thus, `@@hello` is shorthand for `self.__class.hello`. - ```moononly - class Counter - @count: 0 +```moononly +class Counter + @count: 0 - new: => - @@count += 1 + new: => + @@count += 1 - Counter! - Counter! +Counter! +Counter! - print Counter.count -- prints 2 - ``` +print Counter.count -- prints 2 +``` The calling semantics of `@@` are similar to `@`. Calling a `@@` name will pass the class in as the first argument using Lua's colon syntax. - ```moon - @@hello 1,2,3,4 - ``` +```moon +@@hello 1,2,3,4 +``` ### Class Declaration Statements In the body of a class declaration, we can have normal expressions in addition @@ -974,11 +974,11 @@ to key/value pairs. In this context, `self` is equal to the class object. Here is an alternative way to create a class variable compared to what's described above: - ```moon - class Things - @class_var = "hello world" +```moon +class Things + @class_var = "hello world" - ``` +``` These expressions are executed after all the properties have been added to the *base*. @@ -988,15 +988,15 @@ properties. This is convenient for placing private values or helper functions that only the class methods can access: - ```moononly - class MoreThings - secret = 123 - log = (msg) -> print "LOG:", msg +```moononly +class MoreThings + secret = 123 + log = (msg) -> print "LOG:", msg - some_method: => - log "hello world: " .. secret + some_method: => + log "hello world: " .. secret - ``` +``` ### `@` and `@@` Values @@ -1006,17 +1006,17 @@ that name accessed in `self` and `self.__class`. If they are used all by themselves, they are aliases for `self` and `self.__class`. - ```moon - assert @ == self - assert @@ == self.__class - ``` +```moon +assert @ == self +assert @@ == self.__class +``` For example, a quick way to create a new instance of the same class from an instance method using `@@`: - ```moon - some_instance_method = (...) => @@ ... - ``` +```moon +some_instance_method = (...) => @@ ... +``` ### Class Expressions @@ -1024,11 +1024,11 @@ instance method using `@@`: The `class` syntax can also be used as an expression which can be assigned to a variable or explicitly returned. - ```moononly - x = class Bucket - drops: 0 - add_drop: => @drops += 1 - ``` +```moononly +x = class Bucket + drops: 0 + add_drop: => @drops += 1 +``` ### Anonymous classes @@ -1037,19 +1037,19 @@ The name can be left out when declaring a class. The `__name` attribute will be hand side of the assignment is used instead of `nil`. - ```moononly - BigBucket = class extends Bucket - add_drop: => @drops += 10 +```moononly +BigBucket = class extends Bucket + add_drop: => @drops += 10 - assert Bucket.__name == "BigBucket" - ``` +assert Bucket.__name == "BigBucket" +``` You can even leave off the body, meaning you can write a blank anonymous class like this: - ```moononly - x = class - ``` +```moononly +x = class +``` ## Export Statement @@ -1059,38 +1059,38 @@ be declared as local, special syntax is required to declare a variable globally. The export keyword makes it so any following assignments to the specified names will not be assigned locally. - ```moon - export var_name, var_name2 - var_name, var_name3 = "hello", "world" - ``` +```moon +export var_name, var_name2 +var_name, var_name3 = "hello", "world" +``` This is especially useful when declaring what will be externally visible in a module: - ```moon - -- my_module.moon - module "my_module", package.seeall - export print_result +```moon +-- my_module.moon +module "my_module", package.seeall +export print_result - length = (x, y) -> math.sqrt x*x + y*y +length = (x, y) -> math.sqrt x*x + y*y - print_result = (x, y) -> - print "Length is ", length x, y +print_result = (x, y) -> + print "Length is ", length x, y - -- main.moon - require "my_module" +-- main.moon +require "my_module" - my_module.print_result 4, 5 -- prints the result +my_module.print_result 4, 5 -- prints the result - print my_module.length 6, 7 -- errors, `length` not visible - ``` +print my_module.length 6, 7 -- errors, `length` not visible +``` Assignment can be combined with the export keyword to assign to global variables directly: - ```moon - export some_number, message_str = 100, "hello world" - ``` +```moon +export some_number, message_str = 100, "hello world" +``` Additionally, a class declaration can be prefixed with the export keyword in order to export it. @@ -1115,54 +1115,54 @@ In this example we declare the variable `a` in the outer scope so its value can be accessed after the `if` statement. If there was no `local` statement then `a` would only be accessible inside the `if` statement. - ```moon - local a - if something - a = 1 - print a - ``` +```moon +local a +if something + a = 1 +print a +``` `local` can also be used to shadow existing variables for the rest of a scope. - ```moon - x = 10 - if something - local x - x = 12 - print x -- prints 10 - ``` +```moon +x = 10 +if something + local x + x = 12 +print x -- prints 10 +``` When you have one function that calls another, you typically order them such that the second function can access the first. If both functions happen to call each other, then you must forward declare the names: - ```moon - local first, second +```moon +local first, second - first = -> - second! +first = -> + second! - second = -> - first! - ``` +second = -> + first! +``` The same problem occurs with declaring classes and regular values too. Because forward declaring is often better than manually ordering your assigns, a special form of `local` is provided: - ```moon - local * +```moon +local * - first = -> - print data - second! +first = -> + print data + second! - second = -> - first! +second = -> + first! - data = {} - ``` +data = {} +``` `local *` will forward declare all names below it in the current scope. @@ -1175,31 +1175,31 @@ capital letter. Often you want to bring some values from a table into the current scope as local variables by their name. The import statement lets us accomplish this: - ```moon - import insert from table - ``` +```moon +import insert from table +``` The multiple names can be given, each separated by a comma: - ```moon - import C, Ct, Cmt from lpeg - ``` +```moon +import C, Ct, Cmt from lpeg +``` Sometimes a function requires that the table be sent in as the first argument (when using the \\ syntax). As a shortcut, we can prefix the name with a \\ to bind it to that table: - ```moon - -- some object - my_module = - state: 100 - add: (value) => - self.state + value +```moon +-- some object +my_module = + state: 100 + add: (value) => + self.state + value - import \add from my_module +import \add from my_module - print add 22 -- equivalent to calling my_module\get 22 - ``` +print add 22 -- equivalent to calling my_module\get 22 +``` ## With Statement @@ -1217,77 +1217,77 @@ those operations applied to the object we are using `with` on. For example, we work with a newly created object: - ```moon - with Person! - .name = "Oswald" - \add_relative my_dad - \save! - print .name - ``` +```moon +with Person! + .name = "Oswald" + \add_relative my_dad + \save! + print .name +``` The `with` statement can also be used as an expression which returns the value it has been giving access to. - ```moon - file = with File "favorite_foods.txt" - \set_encoding "utf8" - ``` +```moon +file = with File "favorite_foods.txt" + \set_encoding "utf8" +``` Or... - ```moon - create_person = (name, relatives) -> - with Person! - .name = name - \add_relative relative for relative in *relatives +```moon +create_person = (name, relatives) -> + with Person! + .name = name + \add_relative relative for relative in *relatives - me = create_person "Leaf", {dad, mother, sister} - ``` +me = create_person "Leaf", {dad, mother, sister} +``` In this usage, `with` can be seen as a special form of the K combinator. The expression in the `with` statement can also be an assignment, if you want to give a name to the expression. - ```moon - with str = "Hello" - print "original:", str - print "upper:", \upper! - ``` +```moon +with str = "Hello" + print "original:", str + print "upper:", \upper! +``` ## Do When used as a statement, `do` works just like it does in Lua. - ```moon - do - var = "hello" - print var - print var -- nil here - ``` +```moon +do + var = "hello" + print var +print var -- nil here +``` MoonScript's `do` can also be used an expression . Allowing you to combine multiple lines into one. The result of the `do` expression is the last statement in its body. - ```moon - counter = do - i = 0 - -> - i += 1 - i +```moon +counter = do + i = 0 + -> + i += 1 + i - print counter! - print counter! - ``` +print counter! +print counter! +``` - ```moon - tbl = { - key: do - print "assigning key!" - 1234 - } - ``` +```moon +tbl = { + key: do + print "assigning key!" + 1234 +} +``` ## Destructuring Assignment @@ -1302,68 +1302,68 @@ statement. This is best explained with examples. Here is how you would unpack the first two values from a table: - ```moon - thing = {1,2} +```moon +thing = {1,2} - {a,b} = thing - print a,b - ``` +{a,b} = thing +print a,b +``` In the destructuring table literal, the key represents the key to read from the right hand side, and the value represents the name the read value will be assigned to. - ```moon - obj = { - hello: "world" - day: "tuesday" - length: 20 - } +```moon +obj = { + hello: "world" + day: "tuesday" + length: 20 +} - {hello: hello, day: the_day} = obj - print hello, the_day - ``` +{hello: hello, day: the_day} = obj +print hello, the_day +``` This also works with nested data structures as well: - ```moon - obj2 = { - numbers: {1,2,3,4} - properties: { - color: "green" - height: 13.5 - } - } - - {numbers: {first, second}} = obj2 - print first, second, color - ``` +```moon +obj2 = { + numbers: {1,2,3,4} + properties: { + color: "green" + height: 13.5 + } +} + +{numbers: {first, second}} = obj2 +print first, second, color +``` If the destructuring statement is complicated, feel free to spread it out over a few lines. A slightly more complicated example: - ```moon - { - numbers: { first, second } - properties: { - color: color - } - } = obj2 - ``` +```moon +{ + numbers: { first, second } + properties: { + color: color + } +} = obj2 +``` It's common to extract values from at table and assign them the local variables that have the same name as the key. In order to avoid repetition we can use the `:` prefix operator: - ```moon - {:concat, :insert} = table - ``` +```moon +{:concat, :insert} = table +``` This is effectively the same as import, but we can rename fields we want to extract by mixing the syntax: - ```moon - {:mix, :max, random: rand } = math - ``` +```moon +{:mix, :max, random: rand } = math +``` ### Destructuring In Other Places @@ -1371,15 +1371,15 @@ Destructuring can also show up in places where an assignment implicitly takes place. An example of this is a `for` loop: - ```moon - tuples = { - {"hello", "world"} - {"egg", "head"} - } +```moon +tuples = { + {"hello", "world"} + {"egg", "head"} +} - for {left, right} in *tuples - print left, right - ``` +for {left, right} in *tuples + print left, right +``` We know each element in the array table is a two item tuple, so we can unpack it directly in the names clause of the for statement using a destructure. @@ -1399,24 +1399,24 @@ function in the correct context of the object. Its syntax is the same as calling an instance method with the \\ operator but with no argument list provided. - ```moon - my_object = { - value: 1000 - write: => print "the value:", @value - } +```moon +my_object = { + value: 1000 + write: => print "the value:", @value +} - run_callback (func) -> - print "running callback..." - func! +run_callback (func) -> + print "running callback..." + func! - -- this will not work: - -- the function has to no reference to my_object - run_callback my_object.write +-- this will not work: +-- the function has to no reference to my_object +run_callback my_object.write - -- function stub syntax - -- lets us bundle the object into a new function - run_callback my_object\write - ``` +-- function stub syntax +-- lets us bundle the object into a new function +run_callback my_object\write +``` ## The Using Clause; Controlling Destructive Assignment @@ -1424,21 +1424,21 @@ While lexical scoping can be a great help in reducing the complexity of the code we write, things can get unwieldy as the code size increases. Consider the following snippet: - ```moon - i = 100 +```moon +i = 100 - -- many lines of code... +-- many lines of code... - my_func = -> - i = 10 - while i > 0 - print i - i -= 1 +my_func = -> + i = 10 + while i > 0 + print i + i -= 1 - my_func! +my_func! - print i -- will print 0 - ``` +print i -- will print 0 +``` In `my_func`, we've overwritten the value of `i` mistakenly. In this example it @@ -1452,32 +1452,32 @@ The `using` keyword lets us do that. `using nil` makes sure that no closed variables are overwritten in assignment. The `using` clause is placed after the argument list in a function, or in place of it if there are no arguments. - ```moon - i = 100 +```moon +i = 100 - my_func = (using nil) -> - i = "hello" -- a new local variable is created here +my_func = (using nil) -> + i = "hello" -- a new local variable is created here - my_func! - print i -- prints 100, i is unaffected - ``` +my_func! +print i -- prints 100, i is unaffected +``` Multiple names can be separated by commas. Closure values can still be accessed, they just cant be modified: - ```moon - tmp = 1213 - i, k = 100, 50 +```moon +tmp = 1213 +i, k = 100, 50 - my_func = (add using k,i) -> - tmp = tmp + add -- a new local tmp is created - i += tmp - k += tmp +my_func = (add using k,i) -> + tmp = tmp + add -- a new local tmp is created + i += tmp + k += tmp - my_func(22) - print i,k -- these have been updated - ``` +my_func(22) +print i,k -- these have been updated +``` ## Misc. @@ -1497,14 +1497,14 @@ The `with` statement along with implicit return on a file provides a convenient way to do this: - ```moonret - -- my_library.moon - with _M = {} - .SOME_CONSTANT = 100 +```moonret +-- my_library.moon +with _M = {} + .SOME_CONSTANT = 100 - .some_function = -> print .SOME_CONSTANT + .some_function = -> print .SOME_CONSTANT - ``` +``` # MoonScript API @@ -1513,9 +1513,9 @@ way to do this: Upon installing MoonScript, a `moonscript` module is made available. The best use of this module is making your Lua's require function MoonScript aware. - ```lua - require "moonscript" - ``` +```lua +require "moonscript" +``` After `moonscript` is required, Lua's package loader is updated to search for `.moon` files on any subsequent calls to `require`. The search path for `.moon` @@ -1546,27 +1546,27 @@ The MoonScript functions work the same as their counterparts, except they deal with MoonScript code instead of Lua Code. - ```moononly - moonscript = require "moonscript" +```moononly +moonscript = require "moonscript" - fn = moonscript.loadstring 'print "hi!"' - fn! - ``` +fn = moonscript.loadstring 'print "hi!"' +fn! +``` All of these functions can take an optional last argument, a table of options. The only option right now is `implicitly_return_root`. Setting this to `false` makes it so the file does not implicitly return its last statement. - ```moononly - moonscript = require "moonscript" +```moononly +moonscript = require "moonscript" - fn = moonscript.loadstring "10" - print fn! -- prints "10" +fn = moonscript.loadstring "10" +print fn! -- prints "10" - fn = moonscript.loadstring "10", implicitly_return_root: false - print fn! -- prints nothing - ``` +fn = moonscript.loadstring "10", implicitly_return_root: false +print fn! -- prints nothing +``` ## Error Rewriting @@ -1577,10 +1577,10 @@ file. This can make debugging particularly difficult. Consider the following file with a bug (note the invalid `z` variable): - ```moon - add_numbers = (x,y) -> x + z -- 1 - print add_numbers 10,0 -- 2 - ``` +```moon +add_numbers = (x,y) -> x + z -- 1 +print add_numbers 10,0 -- 2 +``` The following error is generated: @@ -1609,23 +1609,23 @@ Lua code from MoonScript code. Here is a quick example of how you would compile a MoonScript string to a Lua String: - ```moononly - parse = require "moonscript.parse" - compile = require "moonscript.compile" +```moononly +parse = require "moonscript.parse" +compile = require "moonscript.compile" - moon_code = [[(-> print "hello world")!]] +moon_code = [[(-> print "hello world")!]] - tree, err = parse.string moon_code - if not tree - error "Parse error: " .. err +tree, err = parse.string moon_code +if not tree + error "Parse error: " .. err - lua_code, err, pos = compile.tree tree - if not lua_code - error compile.format_error err, pos, moon_code +lua_code, err, pos = compile.tree tree +if not lua_code + error compile.format_error err, pos, moon_code - -- our code is ready - print lua_code - ``` +-- our code is ready +print lua_code +``` # Command Line Use @@ -1640,9 +1640,9 @@ Two tools are installed with MoonScript, `moon` and `moonc`. without needing a separate compile step. All MoonsScript files are compiled in memory as they are run. - ```bash - $ moon my_script.moon - ``` +```bash +$ moon my_script.moon +``` Any MoonScript files that are required will also be compiled and run automatically. @@ -1661,9 +1661,9 @@ flag. It takes a list of files, compiles them all, and creates the associated `.lua` files in the same directories. - ```bash - $ moonc my_script1.moon my_script2.moon ... - ``` +```bash +$ moonc my_script1.moon my_script2.moon ... +``` You can control where the compiled files are put using the `-t` flag, followed by a directory. @@ -1702,3 +1702,4 @@ A full list of flags can be seen by passing the `-h` or `--help` flag. THE SOFTWARE. + diff --git a/docs/standard_lib.md b/docs/standard_lib.md index 546a9569..2138f5a5 100644 --- a/docs/standard_lib.md +++ b/docs/standard_lib.md @@ -10,19 +10,19 @@ used to perform various common things. The entire library is currently contained in a single object. We can bring this `moon` object into scope by requiring `"moon"`. - ```moon - require "moon" - -- `moon.p` is the debug printer - moon.p { hello: "world" } - ``` +```moon +require "moon" +-- `moon.p` is the debug printer +moon.p { hello: "world" } +``` If you prefer to just inject all of the functions into the current scope, you can require `"moon.all"` instead. The following has the same effect as above: - ```moon - require "moon.all" - p { hello: "world" } - ``` +```moon +require "moon.all" +p { hello: "world" } +``` All of the functions are compatible with Lua in addition to MoonScript, but some of them only make sense in the context of MoonScript. @@ -53,20 +53,20 @@ The environment of the function is set to a new table whose metatable will use `scope` to look up values. `scope` must be a table. If `scope` does not have an entry for a value, it will fall back on the original environment. - ```moon - my_env = { - secret_function: -> print "shhh this is secret" - say_hi: -> print "hi there!" - } +```moon +my_env = { + secret_function: -> print "shhh this is secret" + say_hi: -> print "hi there!" +} - say_hi = -> print "I am a closure" +say_hi = -> print "I am a closure" - fn = -> - secret_function! - say_hi! +fn = -> + secret_function! + say_hi! - run_with_scope fn, my_env - ``` +run_with_scope fn, my_env +``` Note that any closure values will always take precedence against global name @@ -86,22 +86,22 @@ whose `__index` is set to the next table. Returns the first argument. - ```moon - a = { hello: "world" } - b = { okay: "sure" } +```moon +a = { hello: "world" } +b = { okay: "sure" } - extend a, b +extend a, b - print a.okay - ``` +print a.okay +``` ### `copy(tbl)` Creates a shallow copy of a table, equivalent to: - ```moon - copy = (arg) -> {k,v for k,v in pairs self} - ``` +```moon +copy = (arg) -> {k,v for k,v in pairs self} +``` ## Class/Object Functions @@ -114,28 +114,28 @@ Returns true if `value` is an instance of a MoonScript class, false otherwise. If `value` is an instance of a MoonScript class, then return it's class object. Otherwise, return the result of calling Lua's type method. - ```moon - class MyClass - nil +```moon +class MyClass + nil - x = MyClass! - assert type(x) == MyClass - ``` +x = MyClass! +assert type(x) == MyClass +``` ### `bind_methods(obj)` Takes an instance of an object, returns a proxy to the object whose methods can be called without providing self as the first argument. - ```moon - obj = SomeClass! +```moon +obj = SomeClass! - bound_obj = bind_methods obj +bound_obj = bind_methods obj - -- following have the same effect - obj\hello! - bound_obj.hello! - ``` +-- following have the same effect +obj\hello! +bound_obj.hello! +``` It lazily creates and stores in the proxy table the bound methods when they are first called. @@ -148,18 +148,18 @@ constructor of the class with the `obj` as the receiver. In this example we add the functionality of `First` to an instance of `Second` without ever instancing `First`. - ```moon - class First - new: (@var) => - show_var: => print "var is:", @var +```moon +class First + new: (@var) => + show_var: => print "var is:", @var - class Second - new: => - mixin self, First, "hi" +class Second + new: => + mixin self, First, "hi" - a = Second! - a\show_var! - ``` +a = Second! +a\show_var! +``` Be weary of name collisions when mixing in other classes, names will be overwritten. @@ -170,19 +170,19 @@ Inserts into `obj` methods from `other_obj` whose names are listen in `method_names`. The inserted methods are bound methods that will run with `other_obj` as the receiver. - ```moon - class List - add: (item) => print "adding to", self - remove: (item) => print "removing from", self +```moon +class List + add: (item) => print "adding to", self + remove: (item) => print "removing from", self - class Encapsulation - new: => - @list = List! - mixin_object self, @list, {"add", "remove"} +class Encapsulation + new: => + @list = List! + mixin_object self, @list, {"add", "remove"} - e = Encapsulation! - e.add "something" - ``` +e = Encapsulation! +e.add "something" +``` ### `mixin_table(a, b, [names])` @@ -202,13 +202,14 @@ being iterated over starting with the second item. For example, to sum all numbers in a list: - ```moon - numbers = {4,3,5,6,7,2,3} - sum = fold numbers, (a,b) -> a + b - ``` +```moon +numbers = {4,3,5,6,7,2,3} +sum = fold numbers, (a,b) -> a + b +``` ## Debug Functions ### `debug.upvalue(fn, key[, value])` Gets or sets the value of an upvalue for a function by name. + From becba7f27a28a0842fcf1c4662a90e05dbf2fc07 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 17 Apr 2013 21:08:42 -0700 Subject: [PATCH 094/554] remove outdated compiled documentation --- docs/reference_manual.html | 2416 ------------------------------------ docs/standard_lib.html | 476 ------- 2 files changed, 2892 deletions(-) delete mode 100644 docs/reference_manual.html delete mode 100644 docs/standard_lib.html diff --git a/docs/reference_manual.html b/docs/reference_manual.html deleted file mode 100644 index d768d16b..00000000 --- a/docs/reference_manual.html +++ /dev/null @@ -1,2416 +0,0 @@ - - - - - - MoonScript v0.2.0 - Language Guide - - - - -
-

MoonScript v0.2.0 - Language Guide

-
- - - -
-

MoonScript is a programming language that compiles to -Lua. This guide expects the reader to have basic -familiarity with Lua. For each code snippet below, the MoonScript is on the -left and the compiled Lua is on right right.

- -

The Language

- -

Assignment

- -

Unlike Lua, there is no local keyword. All assignments to names that are not -already defined will be declared as local to the scope of that declaration. If -you wish to create a global variable it must be done using the export -keyword.

- - - - - -
moonscriptlua
hello = "world"
-a,b,c = 1, 2, 3
local hello = "world"
-local a, b, c = 1, 2, 3
- - -

Update Assignment

- -

+=, -=, /=, *=, %=, ..= operators have been added for updating a value by -a certain amount. They are aliases for their expanded equivalents.

- - - - - -
moonscriptlua
x = 0
-x += 10
-
-s = "hello "
-s ..= "world"
local x = 0
-x = x + 10
-local s = "hello "
-s = s .. "world"
- - -

Comments

- -

Like Lua, comments start with -- and continue to the end of the line. -Comments are not written to the output.

- - - - - -
moonscriptlua
-- I am a comment
- - -

Literals & Operators

- -

MoonScript supports all the same primitive literals as Lua and uses the same -syntax. This applies to numbers, strings, booleans, and nil.

- -

MoonScript also supports all the same binary and unary operators. Additionally -!= is as an alias for ~=.

- -

Function Literals

- -

All functions are created using a function expression. A simple function is -denoted using the arrow: ->

- - - - - -
moonscriptlua
my_function = ->
-my_function() -- call the empty function
local my_function
-my_function = function() end
-my_function()
- - -

The body of the function can either be one statement placed directly after the -arrow, or it can be a series of statements indented on the following lines:

- - - - - -
moonscriptlua
func_a = -> print "hello world"
-
-func_b = ->
-  value = 100
-  print "The value:", value
local func_a
-func_a = function()
-  return print("hello world")
-end
-local func_b
-func_b = function()
-  local value = 100
-  return print("The value:", value)
-end
- - -

If a function has no arguments, it can be called using the ! operator, -instead of empty parentheses. The ! invocation is the preferred way to call -functions with no arguments.

- - - - - -
moonscriptlua
func_a!
-func_b()
func_a()
-func_b()
- - -

Functions with arguments can be created by preceding the arrow with a list of -argument names in parentheses:

- - - - - -
moonscriptlua
sum = (x, y) -> print "sum", x + y
local sum
-sum = function(x, y)
-  return print("sum", x + y)
-end
- - -

Functions can be called by listing the values of the arguments after the name -of the variable where the function is stored. When chaining together function -calls, the arguments are applied to the closest function to the left.

- - - - - -
moonscriptlua
sum 10, 20
-print sum 10, 20
-
-a b c "a", "b", "c"
sum(10, 20)
-print(sum(10, 20))
-a(b(c("a", "b", "c")))
- - -

In order to avoid ambiguity in when calling functions, parentheses can also be -used to surround the arguments. This is required here in order to make sure the -right arguments get sent to the right functions.

- - - - - -
moonscriptlua
print "x:", sum(10, 20), "y:", sum(30, 40)
print("x:", sum(10, 20), "y:", sum(30, 40))
- - -

Functions will coerce the last statement in their body into a return statement, -this is called implicit return:

- - - - - -
moonscriptlua
sum = (x, y) -> x + y
-print "The sum is ", sum 10, 20
local sum
-sum = function(x, y)
-  return x + y
-end
-print("The sum is ", sum(10, 20))
- - -

And if you need to explicitly return, you can use the return keyword:

- - - - - -
moonscriptlua
sum = (x, y) -> return x + y
local sum
-sum = function(x, y)
-  return x + y
-end
- - -

Just like in Lua, functions can return multiple values. The last statement must -be a list of values separated by commas:

- - - - - -
moonscriptlua
mystery = (x, y) -> x + y, x - y
-a,b = mystery 10, 20
local mystery
-mystery = function(x, y)
-  return x + y, x - y
-end
-local a, b = mystery(10, 20)
- - -

Fat Arrows

- -

Because it is an idiom in Lua to send an object as the first argument when -calling a method, a special syntax is provided for creating functions which -automatically includes a self argument.

- - - - - -
moonscriptlua
func = (num) => self.value + num
local func
-func = function(self, num)
-  return self.value + num
-end
- - -

Argument Defaults

- -

It is possible to provide default values for the arguments of a function. An -argument is determined to be empty if it’s value is nil. Any nil arguments -that have a default value will be replace before the body of the function is run.

- - - - - -
moonscriptlua
my_function = (name="something", height=100) ->
-  print "Hello I am", name
-  print "My height is", height
local my_function
-my_function = function(name, height)
-  if name == nil then
-    name = "something"
-  end
-  if height == nil then
-    height = 100
-  end
-  print("Hello I am", name)
-  return print("My height is", height)
-end
- - -

An argument default value expression is evaluated in the body of the function -in the order of the argument declarations. For this reason default values have -access to previously declared arguments.

- - - - - -
moonscriptlua
some_args = (x=100, y=x+1000) ->
-  print x + y
local some_args
-some_args = function(x, y)
-  if x == nil then
-    x = 100
-  end
-  if y == nil then
-    y = x + 1000
-  end
-  return print(x + y)
-end
- - -

Considerations

- -

Because of the expressive parentheses-less way of calling functions, some -restrictions must be put in place to avoid parsing ambiguity involving -whitespace.

- -

The minus sign plays two roles, a unary negation operator and a binary -subtraction operator. In order to force subtraction a space must be placed -after the - operator. In order to force a negation, no space must follow -the -. Consider the examples below.

- - - - - -
moonscriptlua
a = x - 10
-b = x-10
-c = x -y
local a = x - 10
-local b = x(-10)
-local c = x(-y)
- - -

The precedence of the first argument of a function call can also be controlled -using whitespace if the argument is a literal string.In Lua, it is common to -leave off parentheses when calling a function with a single string literal.

- -

When there is no space between a variable and a string literal, the -function call takes precedence over any following expressions. No other -arguments can be passed to the function when it is called this way.

- -

Where there is a space following a variable and a string literal, the function -call acts as show above. The string literal belongs to any following -expressions (if they exist), which serves as the argument list.

- - - - - -
moonscriptlua
x = func"hello" + 100
-y = func "hello" + 100
local x = func("hello") + 100
-local y = func("hello" + 100)
- - -

Multi-line arguments

- -

When calling functions that take a large number of arguments, it is convenient -to split the argument list over multiple lines. Because of the white-space -sensitive nature of the language, care must be taken when splitting up the -argument list.

- -

If an argument list is to be continued onto the next line, the current line -must end in a comma. And the following line must be indented more than the -current indentation. Once indented, all other argument lines must be at the -same level of indentation to be part of the argument list

- - - - - -
moonscriptlua
my_func 5,4,3,
-  8,9,10
-
-cool_func 1,2,
-  3,4,
-  5,6,
-  7,8
my_func(5, 4, 3, 8, 9, 10)
-cool_func(1, 2, 3, 4, 5, 6, 7, 8)
- - -

This type of invocation can be nested. The level of indentation is used to -determine to which function the arguments belong to.

- - - - - -
moonscriptlua
my_func 5,6,7,
-  6, another_func 6,7,8,
-    9,1,2,
-  5,4
my_func(5, 6, 7, 6, another_func(6, 7, 8, 9, 1, 2), 5, 4)
- - -

Because tables also use the comma as a delimiter, this -indentation syntax is helpful for letting values be part of the argument list -instead of being part of the table.

- - - - - -
moonscriptlua
x = {
-  1,2,3,4, a_func 4,5,
-    5,6,
-  8,9,10
-}
local x = {
-  1,
-  2,
-  3,
-  4,
-  a_func(4, 5, 5, 6),
-  8,
-  9,
-  10
-}
- - -

Although uncommon, notice how we can give a deeper indentation for function -arguments if we know we will be using a lower indentation futher on.

- - - - - -
moonscriptlua
y = { my_func 1,2,3,
-   4,5,
-  5,6,7
-}
local y = {
-  my_func(1, 2, 3, 4, 5),
-  5,
-  6,
-  7
-}
- - -

The same thing can be done with other block level statements like -conditionals. We can use indentation level to determine what -statement a value belongs to:

- - - - - -
moonscriptlua
if func 1,2,3,
-  "hello",
-  "world"
-    print "hello"
-    print "I am inside if"
-
-if func 1,2,3,
-    "hello",
-    "world"
-  print "hello"
-  print "I am inside if"
if func(1, 2, 3, "hello", "world") then
-  print("hello")
-  print("I am inside if")
-end
-if func(1, 2, 3, "hello", "world") then
-  print("hello")
-  print("I am inside if")
-end
- - -

Table Literals

- -

Like in Lua, tables are delimited in curly braces.

- - - - - -
moonscriptlua
some_values = { 1, 2, 3, 4 }
local some_values = {
-  1,
-  2,
-  3,
-  4
-}
- - -

Unlike Lua, assigning a value to a key in a table is done with : (instead of -=).

- - - - - -
moonscriptlua
some_values = {
-  name: "Bill",
-  age: 200,
-  ["favorite food"]: "rice"
-}
local some_values = {
-  name = "Bill",
-  age = 200,
-  ["favorite food"] = "rice"
-}
- - -

The curly braces can be left off if a single table of key value pairs is being -assigned.

- - - - - -
moonscriptlua
profile = 
-  height: "4 feet",
-  shoe_size: 13,
-  favorite_foods: {"ice cream", "donuts"}
local profile = {
-  height = "4 feet",
-  shoe_size = 13,
-  favorite_foods = {
-    "ice cream",
-    "donuts"
-  }
-}
- - -

Newlines can be used to delimit values instead of a comma (or both):

- - - - - -
moonscriptlua
values = {
-  1,2,3,4
-  5,6,7,8
-  name: "superman"
-  occupation: "crime fighting"
-}
local values = {
-  1,
-  2,
-  3,
-  4,
-  5,
-  6,
-  7,
-  8,
-  name = "superman",
-  occupation = "crime fighting"
-}
- - -

When creating a single line table literal, the curly braces can also be left -off:

- - - - - -
moonscriptlua
my_function dance: "Tango", partner: "none"
-
-y = type: "dog", legs: 4, tails: 1
my_function({
-  dance = "Tango",
-  partner = "none"
-})
-local y = {
-  type = "dog",
-  legs = 4,
-  tails = 1
-}
- - -

The keys of a table literal can be language keywords without being escaped:

- - - - - -
moonscriptlua
tbl = {
-  do: "something"
-  end: "hunger"
-}
local tbl = {
-  ["do"] = "something",
-  ["end"] = "hunger"
-}
- - -

If you are constructing a table out of variables and wish the keys to be the -same as the variable names, then the : prefix operator can be used:

- - - - - -
moonscriptlua
hair = "golden"
-height = 200
-person = { :hair, :height, shoe_size: 40 }
-
-print_table :hair, :height
local hair = "golden"
-local height = 200
-local person = {
-  hair = hair,
-  height = height,
-  shoe_size = 40
-}
-print_table({
-  hair = hair,
-  height = height
-})
- - -

Comprehensions

- -

Compiling provide a convenient syntax for constructing a new table by iterating -over some existing object and applying an expression to its values. There are -two kinds of comprehensions: list comprehensions and table comprehensions. They -both produce Lua tables; list comprehensions accumulate values into an -array-like table, and table comprehensions let you set both the key and the -value on each iteration.

- -

List Comprehensions

- -

The following creates a copy of the items table but with all the values -doubled.

- - - - - -
moonscriptlua
items = { 1, 2, 3, 4 }
-doubled = [item * 2 for i, item in ipairs items]
local items = {
-  1,
-  2,
-  3,
-  4
-}
-local doubled = (function()
-  local _accum_0 = { }
-  local _len_0 = 0
-  for i, item in ipairs(items) do
-    _len_0 = _len_0 + 1
-    _accum_0[_len_0] = item * 2
-  end
-  return _accum_0
-end)()
- - -

The items included in the new table can be restricted with a when clause:

- - - - - -
moonscriptlua
iter = ipairs items
-slice = [item for i, item in iter when i > 1 and i < 3]
local iter = ipairs(items)
-local slice = (function()
-  local _accum_0 = { }
-  local _len_0 = 0
-  for i, item in iter do
-    if i > 1 and i < 3 then
-      _len_0 = _len_0 + 1
-      _accum_0[_len_0] = item
-    end
-  end
-  return _accum_0
-end)()
- - -

Because it is common to iterate over the values of a numerically indexed table, -an * operator is introduced. The doubled example can be rewritten as:

- - - - - -
moonscriptlua
doubled = [item * 2 for item in *items]
local doubled = (function()
-  local _accum_0 = { }
-  local _len_0 = 0
-  local _list_0 = items
-  for _index_0 = 1, #_list_0 do
-    local item = _list_0[_index_0]
-    _len_0 = _len_0 + 1
-    _accum_0[_len_0] = item * 2
-  end
-  return _accum_0
-end)()
- - -

The for and when clauses can be chained as much as desired. The only -requirement is that a comprehension has at least one for clause.

- -

Using multiple for clauses is the same as using nested loops:

- - - - - -
moonscriptlua
x_coords = {4, 5, 6, 7}
-y_coords = {9, 2, 3}
-
-points = [{x,y} for x in *x_coords for y in *y_coords]
local x_coords = {
-  4,
-  5,
-  6,
-  7
-}
-local y_coords = {
-  9,
-  2,
-  3
-}
-local points = (function()
-  local _accum_0 = { }
-  local _len_0 = 0
-  local _list_0 = x_coords
-  for _index_0 = 1, #_list_0 do
-    local x = _list_0[_index_0]
-    local _list_1 = y_coords
-    for _index_0 = 1, #_list_1 do
-      local y = _list_1[_index_0]
-      _len_0 = _len_0 + 1
-      _accum_0[_len_0] = {
-        x,
-        y
-      }
-    end
-  end
-  return _accum_0
-end)()
- - -

Table Comprehensions

- -

The syntax for table comprehensions is very similar, differing by using { and -} and taking two values from each iteration.

- -

This example copies the key-value table thing:

- - - - - -
moonscriptlua
thing = {
-  color: "red"
-  name: "fast"
-  width: 123
-}
-
-thing_copy = {k,v for k,v in pairs thing}
local thing = {
-  color = "red",
-  name = "fast",
-  width = 123
-}
-local thing_copy = (function()
-  local _tbl_0 = { }
-  for k, v in pairs(thing) do
-    _tbl_0[k] = v
-  end
-  return _tbl_0
-end)()
- - -

Table comprehensions, like list comprehensions, also support multiple for and -when clauses. In this example we use a where clause to prevent the value -associated with the color key from being copied.

- - - - - -
moonscriptlua
no_color = {k,v for k,v in pairs thing when k != "color"}
local no_color = (function()
-  local _tbl_0 = { }
-  for k, v in pairs(thing) do
-    if k ~= "color" then
-      _tbl_0[k] = v
-    end
-  end
-  return _tbl_0
-end)()
- - -

The * operator is also supported. Here we create a square root look up table -for a few numbers.

- - - - - -
moonscriptlua
numbers = {1,2,3,4}
-sqrts = {i, math.sqrt i for i in *numbers}
local numbers = {
-  1,
-  2,
-  3,
-  4
-}
-local sqrts = (function()
-  local _tbl_0 = { }
-  local _list_0 = numbers
-  for _index_0 = 1, #_list_0 do
-    local i = _list_0[_index_0]
-    _tbl_0[i] = math.sqrt(i)
-  end
-  return _tbl_0
-end)()
- - -

Slicing

- -

A special syntax is provided to restrict the items that are iterated over when -using the * operator. This is equivalent to setting the iteration bounds and -a step size in a for loop.

- -

Here we can set the minimum and maximum bounds, taking all items with indexes -between 1 and 5 inclusive:

- - - - - -
moonscriptlua
slice = [item for item in *items[1,5]]
local slice = (function()
-  local _accum_0 = { }
-  local _len_0 = 0
-  local _list_0 = items
-  local _max_0 = 5
-  for _index_0 = 1, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do
-    local item = _list_0[_index_0]
-    _len_0 = _len_0 + 1
-    _accum_0[_len_0] = item
-  end
-  return _accum_0
-end)()
- - -

Any of the slice arguments can be left off to use a sensible default. In this -example, if the max index is left off it defaults to the length of the table. -This will take everything but the first element:

- - - - - -
moonscriptlua
slice = [item for item in *items[2,]]
local slice = (function()
-  local _accum_0 = { }
-  local _len_0 = 0
-  local _list_0 = items
-  for _index_0 = 2, #_list_0 do
-    local item = _list_0[_index_0]
-    _len_0 = _len_0 + 1
-    _accum_0[_len_0] = item
-  end
-  return _accum_0
-end)()
- - -

If the minimum bound is left out, it defaults to 1. Here we only provide a step -size and leave the other bounds blank. This takes all odd indexed items: (1, 3, -5, …)

- - - - - -
moonscriptlua
slice = [item for items in *items[,,2]]
local slice = (function()
-  local _accum_0 = { }
-  local _len_0 = 0
-  local _list_0 = items
-  for _index_0 = 1, #_list_0, 2 do
-    local items = _list_0[_index_0]
-    _len_0 = _len_0 + 1
-    _accum_0[_len_0] = item
-  end
-  return _accum_0
-end)()
- - -

For Loop

- -

There are two for loop forms, just like in Lua. A numeric one and a generic one:

- - - - - -
moonscriptlua
for i = 10, 20
-  print i
-
-for k = 1,15,2 -- an optional step provided
-  print k 
-
-for key, value in pairs object
-  print key, value
for i = 10, 20 do
-  print(i)
-end
-for k = 1, 15, 2 do
-  print(k)
-end
-for key, value in pairs(object) do
-  print(key, value)
-end
- - -

The slicing and * operators can be used, just like with table comprehensions:

- - - - - -
moonscriptlua
for item in *items[2,4]
-  print item
local _list_0 = items
-local _max_0 = 4
-for _index_0 = 2, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do
-  local item = _list_0[_index_0]
-  print(item)
-end
- - -

A shorter syntax is also available for all variations when the body is only a -single line:

- - - - - -
moonscriptlua
for item in *items do print item
-
-for j = 1,10,3 do print j
local _list_0 = items
-for _index_0 = 1, #_list_0 do
-  local item = _list_0[_index_0]
-  print(item)
-end
-for j = 1, 10, 3 do
-  print(j)
-end
- - -

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:

- - - - - -
moonscriptlua
doubled_evens = for i=1,20
-  if i % 2 == 0
-    i * 2
-  else
-    i
local doubled_evens = (function()
-  local _accum_0 = { }
-  local _len_0 = 0
-  for i = 1, 20 do
-    local _value_0
-    if i % 2 == 0 then
-      _value_0 = i * 2
-    else
-      _value_0 = i
-    end
-    if _value_0 ~= nil then
-      _len_0 = _len_0 + 1
-      _accum_0[_len_0] = _value_0
-    end
-  end
-  return _accum_0
-end)()
- - -

Filtering out odd numbers:

- - - - - -
moonscriptlua
my_numbers = {1,2,3,4,5,6}
-odds = for x in *my_numbers
-  if x % 2 == 1 then x
local my_numbers = {
-  1,
-  2,
-  3,
-  4,
-  5,
-  6
-}
-local odds = (function()
-  local _accum_0 = { }
-  local _len_0 = 0
-  local _list_0 = my_numbers
-  for _index_0 = 1, #_list_0 do
-    local x = _list_0[_index_0]
-    local _value_0
-    if x % 2 == 1 then
-      _value_0 = x
-    end
-    if _value_0 ~= nil then
-      _len_0 = _len_0 + 1
-      _accum_0[_len_0] = _value_0
-    end
-  end
-  return _accum_0
-end)()
- - -

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.

- - - - - -
moonscriptlua
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
local func_a
-func_a = function()
-  for i = 1, 10 do
-    local _ = i
-  end
-end
-local func_b
-func_b = function()
-  return (function()
-    local _accum_0 = { }
-    local _len_0 = 0
-    for i = 1, 10 do
-      local _value_0 = i
-      if _value_0 ~= nil then
-        _len_0 = _len_0 + 1
-        _accum_0[_len_0] = _value_0
-      end
-    end
-    return _accum_0
-  end)()
-end
-print(func_a())
-print(func_b())
- - -

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:

- - - - - -
moonscriptlua
i = 10
-while i > 0
-  print i
-  i -= 1
-
-while running == true do my_function!
local i = 10
-while i > 0 do
-  print(i)
-  i = i - 1
-end
-while running == true do
-  my_function()
-end
- - -

Like for loops, the while loop can also be used an expression. Additionally, -for a function to return the accumulated value of a while loop, the statement -must be explicitly returned.

- -

Conditionals

- - - - - -
moonscriptlua
have_coins = false
-if have_coins
-  print "Got coins"
-else
-  print "No coins"
local have_coins = false
-if have_coins then
-  print("Got coins")
-else
-  print("No coins")
-end
- - -

A short syntax for single statements can also be used:

- - - - - -
moonscriptlua
have_coins = false
-if have_coins then print "Got coins" else print "No coins"
local have_coins = false
-if have_coins then
-  print("Got coins")
-else
-  print("No coins")
-end
- - -

Because if statements can be used as expressions, this can able be written as:

- - - - - -
moonscriptlua
have_coins = false
-print if have_coins then "Got coins" else "No coins"
local have_coins = false
-print((function()
-  if have_coins then
-    return "Got coins"
-  else
-    return "No coins"
-  end
-end)())
- - -

Conditionals can also be used in return statements and assignments:

- - - - - -
moonscriptlua
is_tall = (name) ->
-  if name == "Rob"
-    true
-  else
-    false
-
-message = if is_tall "Rob"
-  "I am very tall"
-else
-  "I am not so tall"
-
-print message -- prints: I am very tall
local is_tall
-is_tall = function(name)
-  if name == "Rob" then
-    return true
-  else
-    return false
-  end
-end
-local message
-if is_tall("Rob") then
-  message = "I am very tall"
-else
-  message = "I am not so tall"
-end
-print(message)
- - -

Line Decorators

- -

For convenience, the for loop and if statement can be applied to single -statements at the end of the line:

- - - - - -
moonscriptlua
print "hello world" if name == "Rob"
if name == "Rob" then
-  print("hello world")
-end
- - -

And with basic loops:

- - - - - -
moonscriptlua
print "item: ", item for item in *items
local _list_0 = items
-for _index_0 = 1, #_list_0 do
-  local item = _list_0[_index_0]
-  print("item: ", item)
-end
- - -

Switch

- -

The switch statement is shorthand for writing a series of if statements that -check against the same value. Note that the value is only evaluated once. Like -if statements, switches can have an else block to handle no matches. Comparison -is done with the == operator.

- - - - - -
moonscriptlua
name = "Dan"
-switch name
-  when "Robert"
-    print "You are robert"
-  when "Dan"
-    print "Your name, it's Dan"
-  else
-    print "I don't know about your name"
local name = "Dan"
-local _exp_0 = name
-if "Robert" == _exp_0 then
-  print("You are robert")
-elseif "Dan" == _exp_0 then
-  print("Your name, it's Dan")
-else
-  print("I don't know about your name")
-end
- - -

Switches can be used as expressions as well, here we can assign the result of -the switch to a variable:

- - - - - -
moonscriptlua
b = 1
-next_number = switch b
-  when 1
-    2
-  when 2
-    3
-  else
-    error "can't count that high!"
local b = 1
-local next_number
-local _exp_0 = b
-if 1 == _exp_0 then
-  next_number = 2
-elseif 2 == _exp_0 then
-  next_number = 3
-else
-  next_number = error("can't count that high!")
-end
- - -

We can use the then keyword to write a switch’s when block on a single line. -No extra keyword is needed to write the else block on a single line.

- - - - - -
moonscriptlua
msg = switch math.random(1, 5)
-  when 1 then "you are lucky"
-  when 2 then "you are almost lucky"
-  else "not so lucky"
local msg
-local _exp_0 = math.random(1, 5)
-if 1 == _exp_0 then
-  msg = "you are lucky"
-elseif 2 == _exp_0 then
-  msg = "you are almost lucky"
-else
-  msg = "not so lucky"
-end
- - -

It is worth noting the order of the case comparison expression. The case’s -expression is on the left hand side. This can be useful if the case’s -expression wants to overwrite how the comparison is done by defining an eq -metamethod.

- -

Object Oriented Programming

- -

In these examples, the generated Lua code may appear overwhelming. It is best -to focus on the meaning of the MoonScript code at first, then look into the Lua -code if you wish to know the implementation details.

- -

A simple class:

- - - - - -
moonscriptlua
class Inventory
-  new: =>
-    @items = {}
-
-  add_item: (name) =>
-    if @items[name]
-      @items[name] += 1
-    else
-      @items[name] = 1
local Inventory
-Inventory = (function()
-  local _parent_0 = nil
-  local _base_0 = {
-    add_item = function(self, name)
-      if self.items[name] then
-        self.items[name] = self.items[name] + 1
-        return self.items[name]
-      else
-        self.items[name] = 1
-      end
-    end
-  }
-  _base_0.__index = _base_0
-  if _parent_0 then
-    setmetatable(_base_0, _parent_0.__base)
-  end
-  local _class_0 = setmetatable({
-    __init = function(self)
-      self.items = { }
-    end,
-    __base = _base_0,
-    __name = "Inventory",
-    __parent = _parent_0
-  }, {
-    __index = function(cls, name)
-      local val = rawget(_base_0, name)
-      if val == nil and _parent_0 then
-        return _parent_0[name]
-      else
-        return val
-      end
-    end,
-    __call = function(cls, ...)
-      local _self_0 = setmetatable({}, _base_0)
-      cls.__init(_self_0, ...)
-      return _self_0
-    end
-  })
-  _base_0.__class = _class_0
-  return _class_0
-end)()
- - -

A class is declared with a class statement followed by a table-like -declaration where all of the methods and properties are listed.

- -

The new property is special in that it will become the constructor.

- -

Notice how all the methods in the class use the fat arrow function syntax. When -calling methods on a instance, the instance itself is sent in as the first -argument. The fat arrow handles the creation of a self argument.

- -

The @ prefix on a variable name is shorthand for self.. @items becomes -self.items.

- -

Creating an instance of the class is done by calling the name of the class as a -function.

- - - - - -
moonscriptlua
inv = Inventory!
-inv\add_item "t-shirt"
-inv\add_item "pants"
local inv = Inventory()
-inv:add_item("t-shirt")
-inv:add_item("pants")
- - -

Because the instance of the class needs to be sent to the methods when they are -called, the ‘' operator is used.

- -

All properties of a class are shared among the instances. This is fine for -functions, but for other types of objects, undesired results may occur.

- -

Consider the example below, the clothes property is shared amongst all -instances, so modifications to it in one instance will show up in another:

- - - - - -
moonscriptlua
class Person
-  clothes: {}
-  give_item: (name) =>
-    table.insert @clothes, name
-
-a = Person!
-b = Person!
-
-a\give_item "pants"
-b\give_item "shirt"
-
--- will print both pants and shirt
-print item for item in *a.clothes
local Person
-Person = (function()
-  local _parent_0 = nil
-  local _base_0 = {
-    clothes = { },
-    give_item = function(self, name)
-      return table.insert(self.clothes, name)
-    end
-  }
-  _base_0.__index = _base_0
-  if _parent_0 then
-    setmetatable(_base_0, _parent_0.__base)
-  end
-  local _class_0 = setmetatable({
-    __init = function(self, ...)
-      if _parent_0 then
-        return _parent_0.__init(self, ...)
-      end
-    end,
-    __base = _base_0,
-    __name = "Person",
-    __parent = _parent_0
-  }, {
-    __index = function(cls, name)
-      local val = rawget(_base_0, name)
-      if val == nil and _parent_0 then
-        return _parent_0[name]
-      else
-        return val
-      end
-    end,
-    __call = function(cls, ...)
-      local _self_0 = setmetatable({}, _base_0)
-      cls.__init(_self_0, ...)
-      return _self_0
-    end
-  })
-  _base_0.__class = _class_0
-  return _class_0
-end)()
-local a = Person()
-local b = Person()
-a:give_item("pants")
-b:give_item("shirt")
-local _list_0 = a.clothes
-for _index_0 = 1, #_list_0 do
-  local item = _list_0[_index_0]
-  print(item)
-end
- - -

The proper way to avoid this problem is to create the mutable state of the -object in the constructor:

- - - - - -
moonscriptlua
class Person
-  new: =>
-    @clothes = {}
local Person
-Person = (function()
-  local _parent_0 = nil
-  local _base_0 = { }
-  _base_0.__index = _base_0
-  if _parent_0 then
-    setmetatable(_base_0, _parent_0.__base)
-  end
-  local _class_0 = setmetatable({
-    __init = function(self)
-      self.clothes = { }
-    end,
-    __base = _base_0,
-    __name = "Person",
-    __parent = _parent_0
-  }, {
-    __index = function(cls, name)
-      local val = rawget(_base_0, name)
-      if val == nil and _parent_0 then
-        return _parent_0[name]
-      else
-        return val
-      end
-    end,
-    __call = function(cls, ...)
-      local _self_0 = setmetatable({}, _base_0)
-      cls.__init(_self_0, ...)
-      return _self_0
-    end
-  })
-  _base_0.__class = _class_0
-  return _class_0
-end)()
- - -

Inheritance

- -

The extends keyword can be used in a class declaration to inherit the -properties and methods from another class.

- - - - - -
moonscriptlua
class BackPack extends Inventory
-  size: 10
-  add_item: (name) =>
-    if #@items > size then error "backpack is full"
-    super name
local BackPack
-BackPack = (function()
-  local _parent_0 = Inventory
-  local _base_0 = {
-    size = 10,
-    add_item = function(self, name)
-      if #self.items > size then
-        error("backpack is full")
-      end
-      return _parent_0.add_item(self, name)
-    end
-  }
-  _base_0.__index = _base_0
-  if _parent_0 then
-    setmetatable(_base_0, _parent_0.__base)
-  end
-  local _class_0 = setmetatable({
-    __init = function(self, ...)
-      if _parent_0 then
-        return _parent_0.__init(self, ...)
-      end
-    end,
-    __base = _base_0,
-    __name = "BackPack",
-    __parent = _parent_0
-  }, {
-    __index = function(cls, name)
-      local val = rawget(_base_0, name)
-      if val == nil and _parent_0 then
-        return _parent_0[name]
-      else
-        return val
-      end
-    end,
-    __call = function(cls, ...)
-      local _self_0 = setmetatable({}, _base_0)
-      cls.__init(_self_0, ...)
-      return _self_0
-    end
-  })
-  _base_0.__class = _class_0
-  return _class_0
-end)()
- - -

Here we extend our Inventory class, and limit the amount of items it can carry.

- -

Super

- -

super is a special keyword that can be used in two different ways: It can be -treated as an object, or it can be called like a function. It only has special -functionality when inside a class.

- -

When called as a function, it will call the function of the same name in the -parent class. The current self will automatically be passed as the first -argument. (As seen in the inheritance example above)

- -

When super is used as a normal value, it is a reference to the parent class -object.

- -

It can be accessed like any of object in order to retrieve values in the -parent class that might have been shadowed by the child class.

- -

When the \ calling operator is used with super, self is inserted as the -first argument instead of the value of super itself. When using . to -retrieve a function, the raw function is returned.

- -

A few examples of using super in different ways:

- - - - - -
moonscriptlua
class MyClass extends ParentClass
-  a_method: =>
-    -- the following have the same effect:
-    super "hello", "world"
-    super\a_method "hello", "world"
-    super.a_method self, "hello", "world"
-
-    -- super as a value is equal to the parent class:
-    assert super == ParentClass
local MyClass
-MyClass = (function()
-  local _parent_0 = ParentClass
-  local _base_0 = {
-    a_method = function(self)
-      _parent_0.a_method(self, "hello", "world")
-      _parent_0.a_method(self, "hello", "world")
-      _parent_0.a_method(self, "hello", "world")
-      return assert(_parent_0 == ParentClass)
-    end
-  }
-  _base_0.__index = _base_0
-  if _parent_0 then
-    setmetatable(_base_0, _parent_0.__base)
-  end
-  local _class_0 = setmetatable({
-    __init = function(self, ...)
-      if _parent_0 then
-        return _parent_0.__init(self, ...)
-      end
-    end,
-    __base = _base_0,
-    __name = "MyClass",
-    __parent = _parent_0
-  }, {
-    __index = function(cls, name)
-      local val = rawget(_base_0, name)
-      if val == nil and _parent_0 then
-        return _parent_0[name]
-      else
-        return val
-      end
-    end,
-    __call = function(cls, ...)
-      local _self_0 = setmetatable({}, _base_0)
-      cls.__init(_self_0, ...)
-      return _self_0
-    end
-  })
-  _base_0.__class = _class_0
-  return _class_0
-end)()
- - -

super can also be used on left side of a Function Stub. -The only major difference is that instead of the resulting function being bound -to the value of super, it is bound to self.

- -

Types

- -

Every instance of a class carries its type with it. This is stored in the -special __class property. This property holds the class object. The class -object is what we call to build a new instance. We can also index the class -object to retrieve class methods and properties.

- - - - - -
moonscriptlua
b = BackPack!
-assert b.__class == BackPack
-
-print BackPack.size -- prints 10
local b = BackPack()
-assert(b.__class == BackPack)
-print(BackPack.size)
- - -

Export Statement

- -

Because, by default, all assignments to variables that are not lexically visible will -be declared as local, special syntax is required to declare a variable globally.

- -

The export keyword makes it so any following assignments to the specified names -will not be assigned locally.

- - - - - -
moonscriptlua
export var_name, var_name2
-var_name, var_name3 = "hello", "world"
local var_name3
-var_name, var_name3 = "hello", "world"
- - -

This is especially useful when declaring what will be externally visible in a -module:

- - - - - -
moonscriptlua
-- my_module.moon
-module "my_module", package.seeall
-export print_result
-
-length = (x, y) -> math.sqrt x*x + y*y
-
-print_result = (x, y) ->
-  print "Length is ", length x, y
-
--- main.moon
-require "my_module"
-
-my_module.print_result 4, 5 -- prints the result
-
-print my_module.length 6, 7 -- errors, `length` not visible
module("my_module", package.seeall)
-local length
-length = function(x, y)
-  return math.sqrt(x * x + y * y)
-end
-print_result = function(x, y)
-  return print("Length is ", length(x, y))
-end
-require("my_module")
-my_module.print_result(4, 5)
-print(my_module.length(6, 7))
- - -

Assignment can be combined with the export keyword to assign to global -variables directly:

- - - - - -
moonscriptlua
export some_number, message_str = 100, "hello world"
some_number, message_str = 100, "hello world"
- - -

Additionally, a class declaration can be prefixed with the export keyword in -order to export it.

- -

Export All & Export Proper

- -

The export statement can also take special symbols * and ^.

- -

export * will cause any name declared after the statement to be exported in the -current scope. export ^ will export all proper names, names that begin with a -capital letter.

- -

Import Statement

- -

Often you want to bring some values from a table into the current scope as -local variables by their name. The import statement lets us accomplish this:

- - - - - -
moonscriptlua
import insert from table
local insert = table.insert
- - -

The multiple names can be given, each separated by a comma:

- - - - - -
moonscriptlua
import C, Ct, Cmt from lpeg
local C, Ct, Cmt = lpeg.C, lpeg.Ct, lpeg.Cmt
- - -

Sometimes a function requires that the table be sent in as the first argument -(when using the \ syntax). As a shortcut, we can prefix the name -with a \ to bind it to that table:

- - - - - -
moonscriptlua
-- some object
-my_module =
-    state: 100
-    add: (value) =>
-        self.state + value
-
-import \add from my_module
-
-print add(22) -- equivalent to calling my_module\get 22
local my_module = {
-  state = 100,
-  add = function(self, value)
-    return self.state + value
-  end
-}
-local add = (function()
-  local _base_0 = my_module
-  local _fn_0 = _base_0.add
-  return function(...)
-    return _fn_0(_base_0, ...)
-  end
-end)()
-print(add(22))
- - -

With Statement

- -

A common pattern involving the creation of an object is calling a series of -functions and setting a series of properties immediately after creating it.

- -

This results in repeating the name of the object multiple times in code, adding -unnecessary noise. A common solution to this is to pass a table in as an -argument which contains a collection of keys and values to overwrite. The -downside to this is that the constructor of this object must support this form.

- -

The with block helps to alleviate this. Within a with block we can use a -special statements that begin with either . or \ which represent -those operations applied to the object we are using with on.

- -

For example, we work with a newly created object:

- - - - - -
moonscriptlua
with Person!
-  .name = "Oswald"
-  \add_relative my_dad
-  \save!
-  print .name
do
-  local _with_0 = Person()
-  _with_0.name = "Oswald"
-  _with_0:add_relative(my_dad)
-  _with_0:save()
-  print(_with_0.name)
-end
- - -

The with statement can also be used as an expression which returns the value -it has been giving access to.

- - - - - -
moonscriptlua
file = with File "favorite_foods.txt"
-  \set_encoding "utf8"
local file
-do
-  local _with_0 = File("favorite_foods.txt")
-  _with_0:set_encoding("utf8")
-  file = _with_0
-end
- - -

Or…

- - - - - -
moonscriptlua
create_person = (name,  relatives) ->
-  with Person!
-    .name = name
-    \add_relative relative for relative in *relatives
-
-me = create_person "Leaf", {dad, mother, sister}
local create_person
-create_person = function(name, relatives)
-  do
-    local _with_0 = Person()
-    _with_0.name = name
-    local _list_0 = relatives
-    for _index_0 = 1, #_list_0 do
-      local relative = _list_0[_index_0]
-      _with_0:add_relative(relative)
-    end
-    return _with_0
-  end
-end
-local me = create_person("Leaf", {
-  dad,
-  mother,
-  sister
-})
- - -

Function Stubs

- -

It is common to pass a function from an object around as a value, for example, -passing an instance method into a function as a callback. If the function -expects the object it is operating on as the first argument then you must -somehow bundle that object with the function so it can be called properly.

- -

The function stub syntax is a shorthand for creating a new closure function -that bundles both the object and function. This new function calls the wrapped -function in the correct context of the object.

- -

Its syntax is the same as calling an instance method with the \ operator but -with no argument list provided.

- - - - - -
moonscriptlua
my_object = {
-  value: 1000
-  write: => print "the value:", @value
-}
-
-run_callback (func) ->
-  print "running callback..."
-  func!
-
--- this will not work:
--- the function has to no reference to my_object
-run_callback my_object.write
-
--- function stub syntax
--- lets us bundle the object into a new function
-run_callback my_object\write
local my_object = {
-  value = 1000,
-  write = function(self)
-    return print("the value:", self.value)
-  end
-}
-run_callback(function(func)
-  print("running callback...")
-  return func()
-end)
-run_callback(my_object.write)
-run_callback((function()
-  local _base_0 = my_object
-  local _fn_0 = _base_0.write
-  return function(...)
-    return _fn_0(_base_0, ...)
-  end
-end)())
- - -

The Using Clause; Controlling Destructive Assignment

- -

While lexical scoping can be a great help in reducing the complexity of the -code we write, things can get unwieldy as the code size increases. Consider -the following snippet:

- - - - - -
moonscriptlua
i = 100
-
--- many lines of code...
-
-my_func = ->
-    i = 10
-    while i > 0
-        print i
-        i -= 1
-
-my_func()
-
-print i -- will print 0
local i = 100
-local my_func
-my_func = function()
-  i = 10
-  while i > 0 do
-    print(i)
-    i = i - 1
-  end
-end
-my_func()
-print(i)
- - -

In my_func, we've overwritten the value of i mistakenly. In this example it -is quite obvious, but consider a large, or foreign code base where it isn’t -clear what names have already been declared.

- -

It would be helpful to say which variables from the enclosing scope we intend -on change, in order to prevent us from changing others by accident.

- -

The using keyword lets us do that. using nil makes sure that no closed -variables are overwritten in assignment. The using clause is placed after the -argument list in a function, or in place of it if there are no arguments.

- - - - - -
moonscriptlua
i = 100
-
-my_func = (using nil) ->
-    i = "hello" -- a new local variable is created here
-
-my_func()
-print i -- prints 100, i is unaffected
local i = 100
-local my_func
-my_func = function()
-  local i = "hello"
-end
-my_func()
-print(i)
- - -

Multiple names can be separated by commas. Closure values can still be -accessed, they just cant be modified:

- - - - - -
moonscriptlua
tmp = 1213
-i, k = 100, 50
-
-my_func = (add using k,i) ->
-    tmp = tmp + add -- a new local tmp is created 
-    i += tmp
-    k += tmp
-
-my_func(22)
-print i,k -- these have been updated
local tmp = 1213
-local i, k = 100, 50
-local my_func
-my_func = function(add)
-  local tmp = tmp + add
-  i = i + tmp
-  k = k + tmp
-  return k
-end
-my_func(22)
-print(i, k)
- - -

MoonScript API

- -

moonscript Module

- -

Upon installing MoonScript, a moonscript module is made available. The best -use of this module is making your Lua’s require function MoonScript aware.

- - - - - -
moonscriptlua
require "moonscript"
require("moonscript")
- - -

After moonscript is required, Lua’s package loader is updated to search for -.moon files on any subsequent calls to require. The search path for .moon -files is based on the current package.path value in Lua when moonscript is -required. Any search paths in package.path ending in .lua are copied, -rewritten to end in .moon, and then inserted in package.moonpath.

- -

The moonloader is the function that is responsible for searching -package.moonpath for a file available to be included. It is inserted in the -second position of the package.loaders table. This means that a matching .moon file -will be loaded over a matching .lua file that has the same base name.

- -

For more information on Lua’s package.loaders see Lua Reference Manual -— -package.loaders

- -

The moonloader, when finding a valid path to a .moon file, will parse and -compile the file in memory. The code is then turned into a function using the -built in load function, which is run as the module.

- -

Error Rewriting

- -

Runtime errors are given special attention when using the moonloader. -Because we start off as MoonScript, but run code as Lua, errors that happen -during runtime report their line numbers as they are in the compiled file. This -can make debugging particularly difficult.

- -

Consider the following file with a bug:

- - - - - -
moonscriptlua
add_numbers = (x,y) -> x + z
-print add_numbers 10,0
local add_numbers
-add_numbers = function(x, y)
-  return x + z
-end
-print(add_numbers(10, 0))
- - -

The following error is generated:

- -
moon:err.moon:1: attempt to perform arithmetic on global 'z' (a nil value)
-stack traceback:
-    err.moon:1: in function 'add_numbers'
-    err.moon:2: in main chunk
-
- -

Instead of the error being reported on line number 3, where it appears in the -Lua file, it is reported on line 1, where the faulty line originated. The -entire stack trace is rewritten in addition to the error.

- -

Programmatically Compiling

- -

The MoonScript module also contains methods for parsing MoonScript text into an -abstract syntax tree, and compiling an instance of a tree into Lua source code.

- -

Knowledge of this API may be useful for creating tools to aid the generation of -Lua code from MoonScript code.

- -

Here is a quick example of how you would compile a MoonScript string to a Lua -String:

- - - - - -
moonscriptlua
require "moonscript.parse"
-require "moonscript.compile"
-
-import parse, compile from moonscript
-
-moon_code = [[(-> print "hello world")!]]
-
-tree, err = parse.string moon_code
-if not tree
-  error "Parse error: " .. err
-
-lua_code, err, pos = compile.tree tree
-if not lua_code
-  error compile.format_error err, pos, moon_code
-
--- our code is ready
-print lua_code
require("moonscript.parse")
-require("moonscript.compile")
-local parse, compile = moonscript.parse, moonscript.compile
-local moon_code = [[(-> print "hello world")!]]
-local tree, err = parse.string(moon_code)
-if not tree then
-  error("Parse error: " .. err)
-end
-local lua_code, pos
-lua_code, err, pos = compile.tree(tree)
-if not lua_code then
-  error(compile.format_error(err, pos, moon_code))
-end
-print(lua_code)
- - -

Command Line Use

- -

Two tools are installed with MoonScript, moon and moonc.

- -

moonc is for compiling MoonScript code to Lua.
-moon is for running MoonsScript code directly.

- -

moon

- -

moon can be used to run MoonsScript files directly from the command line, -without needing a separate compile step. All MoonsScript files are compiled in -memory as they are run.

- -
$ moon my_script.moon
-
- - -

Any MoonScript files that are required will also be compiled and run -automatically.

- -

When an error occurs during runtime, the stack trace is rewritten to give line -numbers from the original .moon file.

- -

If you want to disable error rewriting, you can pass the --d flag. A full list of flags can be seen by passing the -h or --help -flag.

- -

moonc

- -

moonc is used for transforming MoonsScript files into Lua files. -It takes a list of files, compiles them all, and creates the associated .lua -files in the same directories.

- -
$ moonc my_script1.moon my_script2.moon ...
-
- - -

You can control where the compiled files are put using the -t flag, followed -by a directory.

- -

moonc can also take a directory as an argument, and it will recursively scan -for all MoonScript files and compile them.

- -

moonc can write to standard out by passing the -p flag.

- -

Combined with linotify on linux, the -w flag can be used to watch all files -that match the given search path for changes, and then compile them only when -required.

- -

A full list of flags can be seen by passing the -h or --help flag.

- -

License (MIT)

- -
Copyright (C) 2011 by Leaf Corcoran
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-
- -
- - - - - - - - diff --git a/docs/standard_lib.html b/docs/standard_lib.html deleted file mode 100644 index 4c64f016..00000000 --- a/docs/standard_lib.html +++ /dev/null @@ -1,476 +0,0 @@ - - - - - - MoonScript v0.2.0 - Standard Library - - - - -
-

MoonScript v0.2.0 - Standard Library

-
- - - -
-

The MoonScript installation comes with a small kernel of functions that can be -used to perform various common things.

- -

The entire library is currently contained in a single object. We can bring this -moon object into scope by requiring "moon".

- -
require "moon"
--- `moon.p` is the debug printer
-moon.p { hello: "world" }
-
- - -

If you prefer to just inject all of the functions into the current scope, you -can require "moon.all" instead. The following has the same effect as above:

- -
require "moon.all"
-p { hello: "world" }
-
- - -

All of the functions are compatible with Lua in addition to MoonScript, but -some of them only make sense in the context of MoonScript.

- -

MoonScript Standard Library

- -

This is an overview of all the included functions. -All of the examples assume that the standard library has been included with -require "moon.all".

- -

Printing Functions

- -

p(arg)

- -

Prints a formatted version of an object. Excellent for inspecting the contents -of a table.

- -

Table Functions

- -

run_with_scope(fn, scope, [args...])

- -

Mutates the environment of function fn and runs the function with any extra -arguments in args.... Returns the result of the function.

- -

The environment of the function is set to a new table whose metatable will use -scope to look up values. scope must be a table. If scope does not have an -entry for a value, it will fall back on the original environment.

- -
my_env = {
-  secret_function: -> print "shhh this is secret"
-  say_hi: -> print "hi there!"
-}
-
-say_hi = -> print "I am a closure"
-
-fn = ->
-  secret_function!
-  say_hi!
-
-run_with_scope fn, my_env
-
- - -

Note that any closure values will always take precedence against global name -lookups in the environment. In the example above, the say_hi in the -environment has been shadowed by the local variable say_hi.

- -

defaultbl([tbl,] fn)

- -

Sets the __index of table tbl to use the function fn to generate table -values when a missing key is looked up.

- -

extend(arg1, arg2, [rest...])

- -

Chains together a series of tables by their metatable’s __index property. -Overwrites the metatable of all objects exept for the last with a new table -whose __index is set to the next table.

- -

Returns the first argument.

- -
a = { hello: "world" }
-b = { okay: "sure" }
-
-extend a, b
-
-print a.okay
-
- - -

copy(tbl)

- -

Creates a shallow copy of a table, equivalent to:

- -
copy = (arg) -> {k,v for k,v in pairs self}
-
- - -

Class/Object Functions

- -

is_object(value)

- -

Returns true if value is an instance of a MoonScript class, false otherwise.

- -

type(value)

- -

If value is an instance of a MoonScript class, then return it’s class object. -Otherwise, return the result of calling Lua’s type method.

- -
class MyClass
-  nil
-
-x = MyClass!
-assert type(x) == MyClass
-
- - -

bind_methods(obj)

- -

Takes an instance of an object, returns a proxy to the object whose methods can -be called without providing self as the first argument.

- -
obj = SomeClass!
-
-bound_obj = bind_methods obj
-
--- following have the same effect
-obj\hello!
-bound_obj.hello!
-
- - -

It lazily creates and stores in the proxy table the bound methods when they -are first called.

- -

mixin(obj, class, [args...])

- -

Copies the methods of a class cls into the table obj, then calls the -constructor of the class with the obj as the receiver.

- -

In this example we add the functionality of First to an instance of Second -without ever instancing First.

- -
class First
-  new: (@var) =>
-  show_var: => print "var is:", @var
-
-class Second
-  new: =>
-    mixin self, First, "hi"
-
-a = Second!
-a\show_var!
-
- - -

Be weary of name collisions when mixing in other classes, names will be -overwritten.

- -

mixin_object(obj, other_obj, method_names)

- -

Inserts into obj methods from other_obj whose names are listen in -method_names. The inserted methods are bound methods that will run with -other_obj as the receiver.

- -
class List 
-  add: (item) => print "adding to", self
-  remove: (item) => print "removing from", self
-
-class Encapsulation
-  new: =>
-    @list = List!
-    mixin_object self, @list, {"add", "remove"}
-
-e = Encapsulation!
-e.add "something"
-
- - -

mixin_table(a, b, [names])

- -

Copies the elements of table b into table a. If names is provided, then -only those names are copied.

- -

Misc Functions

- -

fold(items, fn)

- -

Calls function fn repeatedly with the accumulated value and the current value -by iterating over items. The accumulated value is the result of the last call -to fn, or, in the base case, the first value. The current value is the value -being iterated over starting with the second item.

- -

items is a normal array table.

- -

For example, to sum all numbers in a list:

- -
numbers = {4,3,5,6,7,2,3}
-sum = fold numbers, (a,b) -> a + b
-
- - -

Debug Functions

- -

debug.upvalue(fn, key[, value])

- -

Gets or sets the value of an upvalue for a function by name.

- -
- - - - - - - - From ce3d4adbb1e41445e284ed4a9687edff9a929722 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 17 Apr 2013 21:19:40 -0700 Subject: [PATCH 095/554] allow line breaks inside of quote strings --- docs/reference.md | 16 ++++++++++++---- moonscript/compile/value.lua | 7 +++++++ moonscript/compile/value.moon | 8 ++++++++ moonscript/parse.lua | 2 +- tests/inputs/literals.moon | 13 +++++++++++++ tests/outputs/literals.lua | 5 ++++- 6 files changed, 45 insertions(+), 6 deletions(-) diff --git a/docs/reference.md b/docs/reference.md index 1f357bbd..2d2b158f 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -64,11 +64,19 @@ Comments are not written to the output. ## Literals & Operators -MoonScript supports all the same primitive literals as Lua and uses the same -syntax. This applies to numbers, strings, booleans, and `nil`. +All of the primitive literals in Lua can be used. This applies to numbers, +strings, booleans, and `nil`. -MoonScript also supports all the same binary and unary operators. Additionally -`!=` is as an alias for `~=`. +All of Lua's binary and unary operators are available. Additionally `!=` is as +an alias for `~=`. + +Unlike Lua, Line breaks are allowed inside of single and double quote strings +without an escape sequence: + +```moon +some_string = "Here is a string + that has a line break in it." +``` ## Function Literals diff --git a/moonscript/compile/value.lua b/moonscript/compile/value.lua index 19a160f2..28b2cb3b 100644 --- a/moonscript/compile/value.lua +++ b/moonscript/compile/value.lua @@ -13,6 +13,10 @@ end local concat, insert = table.concat, table.insert local unpack = util.unpack local table_delim = "," +local string_chars = { + ["\r"] = "\\r", + ["\n"] = "\\n" +} local value_compilers = { exp = function(self, node) local _comp @@ -61,6 +65,9 @@ local value_compilers = { string = function(self, node) local _, delim, inner = unpack(node) local end_delim = delim:gsub("%[", "]") + if delim == "'" or delim == '"' then + inner = inner:gsub("[\r\n]", string_chars) + end return delim .. inner .. end_delim end, chain = function(self, node) diff --git a/moonscript/compile/value.moon b/moonscript/compile/value.moon index 52006edf..89b21e92 100644 --- a/moonscript/compile/value.moon +++ b/moonscript/compile/value.moon @@ -9,6 +9,11 @@ import unpack from util table_delim = "," +string_chars = { + "\r": "\\r" + "\n": "\\n" +} + value_compilers = -- list of values separated by binary operators exp: (node) => @@ -31,6 +36,9 @@ value_compilers = string: (node) => _, delim, inner = unpack node end_delim = delim\gsub "%[", "]" + if delim == "'" or delim == '"' + inner = inner\gsub "[\r\n]", string_chars + delim..inner..end_delim chain: (node) => diff --git a/moonscript/parse.lua b/moonscript/parse.lua index f6d04c2c..a4e36b95 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -227,7 +227,7 @@ local function symx(chars) end local function simple_string(delim, allow_interpolation) - local inner = P('\\'..delim) + "\\\\" + (1 - S('\r\n'..delim)) + local inner = P('\\'..delim) + "\\\\" + (1 - P(delim)) if allow_interpolation then inter = symx"#{" * V"Exp" * sym"}" inner = (C((inner - inter)^1) + inter / mark"interpolate")^0 diff --git a/tests/inputs/literals.moon b/tests/inputs/literals.moon index 125b494e..7f58b6ee 100644 --- a/tests/inputs/literals.moon +++ b/tests/inputs/literals.moon @@ -23,3 +23,16 @@ "another world" 'what world' + + +" +hello world +" + +'yeah +what is going on +here is something cool' + + +nil + diff --git a/tests/outputs/literals.lua b/tests/outputs/literals.lua index 93c06293..b49c57a8 100644 --- a/tests/outputs/literals.lua +++ b/tests/outputs/literals.lua @@ -14,4 +14,7 @@ _ = [[ hello world ]] _ = [=[ hello world ]=] _ = [====[ hello world ]====] _ = "another world" -return 'what world' \ No newline at end of file +_ = 'what world' +_ = "\nhello world\n" +_ = 'yeah\nwhat is going on\nhere is something cool' +return nil \ No newline at end of file From a4fbc976d9c642924047f416f10f24ecbda8ebae Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 25 Apr 2013 09:40:58 -0700 Subject: [PATCH 096/554] don't allow lpeg 0.11 #94 --- moonscript-dev-1.rockspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/moonscript-dev-1.rockspec b/moonscript-dev-1.rockspec index 457c0169..a5323882 100644 --- a/moonscript-dev-1.rockspec +++ b/moonscript-dev-1.rockspec @@ -14,7 +14,7 @@ description = { dependencies = { "lua >= 5.1", - "lpeg >= 0.10", + "lpeg >= 0.10, ~= 0.11", "alt-getopt >= 0.7", "luafilesystem >= 1.5" } From 1a436b79b2ef64eebde579833519e498543fdbc2 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 6 Jun 2013 16:55:59 -0700 Subject: [PATCH 097/554] { a : b } doesn't do self-assign #98 --- moonscript/parse.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/moonscript/parse.lua b/moonscript/parse.lua index a4e36b95..13001bc3 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -575,7 +575,7 @@ local build_grammar = wrap_env(function() op"*" + op"^" + Ct(NameList) * (sym"=" * Ct(ExpListLow))^-1) / mark"export", - KeyValue = (sym":" * Name) / self_assign + Ct((KeyName + sym"[" * Exp * sym"]" + DoubleString + SingleString) * symx":" * (Exp + TableBlock)), + KeyValue = (sym":" * -SomeSpace * Name) / self_assign + Ct((KeyName + sym"[" * Exp * sym"]" + DoubleString + SingleString) * symx":" * (Exp + TableBlock)), KeyValueList = KeyValue * (sym"," * KeyValue)^0, KeyValueLine = CheckIndent * KeyValueList * sym","^-1, From 6867817df49fbb69d8ca461ffc084d2b6158a919 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 6 Jun 2013 17:27:49 -0700 Subject: [PATCH 098/554] mention tests in readme --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 52fa23f5..de9f83d3 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,16 @@ See . Online demo/compiler at . + +## Running Tests + +Tests are written in MoonScript using [Busted](http://olivinelabs.com/busted/). +In order to run the tests you must compile the test runner file before executing. + +```bash +moonc test2.moon && busted test2.lua +``` + ## License (MIT) Copyright (C) 2012 by Leaf Corcoran From 71dad43c031a5d3e734109135ea8b7b630997494 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 6 Jun 2013 17:29:12 -0700 Subject: [PATCH 099/554] import can have free whitespace around imported names --- moonscript/parse.lua | 4 ++-- tests/inputs/import.moon | 26 ++++++++++++++++++++++++++ tests/outputs/import.lua | 15 +++++++++++++++ 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 13001bc3..e3966c74 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -409,9 +409,9 @@ local build_grammar = wrap_env(function() Local = key"local" * ((op"*" + op"^") / mark"declare_glob" + Ct(NameList) / mark"declare_with_shadows"), - Import = key"import" * Ct(ImportNameList) * key"from" * Exp / mark"import", + Import = key"import" * Ct(ImportNameList) * SpaceBreak^0 * key"from" * Exp / mark"import", ImportName = (sym"\\" * Ct(Cc"colon_stub" * Name) + Name), - ImportNameList = ImportName * (sym"," * ImportName)^0, + ImportNameList = SpaceBreak^0 * ImportName * ((SpaceBreak^1 + sym"," * SpaceBreak^0) * ImportName)^0, NameList = Name * (sym"," * Name)^0, diff --git a/tests/inputs/import.moon b/tests/inputs/import.moon index dac41017..d86d7243 100644 --- a/tests/inputs/import.moon +++ b/tests/inputs/import.moon @@ -20,3 +20,29 @@ import something from a table if indent import okay, \well from tables[100] +do + import a, b, c from z + +do + import a, + b, c from z + +do + import a + b + c from z + +do + import + a + b + c from z + + +do + import + a + b + c + from z + diff --git a/tests/outputs/import.lua b/tests/outputs/import.lua index 9c3cf0e4..1bd218e4 100644 --- a/tests/outputs/import.lua +++ b/tests/outputs/import.lua @@ -42,4 +42,19 @@ if indent then end end)() end +end +do + a, b, c = z.a, z.b, z.c +end +do + a, b, c = z.a, z.b, z.c +end +do + a, b, c = z.a, z.b, z.c +end +do + a, b, c = z.a, z.b, z.c +end +do + a, b, c = z.a, z.b, z.c end \ No newline at end of file From 9ac382fc497aef60329d57a6c1fd53894b686947 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 6 Jun 2013 19:29:17 -0700 Subject: [PATCH 100/554] destructure from value directly if local --- moonscript/compile.lua | 10 ++++++ moonscript/compile.moon | 8 +++++ moonscript/transform.lua | 6 ++-- moonscript/transform.moon | 7 ++-- moonscript/transform/destructure.lua | 10 +++--- moonscript/transform/destructure.moon | 11 ++++--- tests/inputs/destructure.moon | 18 +++++++++++ tests/outputs/destructure.lua | 46 +++++++++++++++------------ 8 files changed, 79 insertions(+), 37 deletions(-) diff --git a/moonscript/compile.lua b/moonscript/compile.lua index 60087495..1792ac5d 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -429,6 +429,16 @@ do return yes end end, + is_local = function(self, node) + local t = mtype(node) + if t == "string" then + return self:has_name(node, false) + end + if t == NameProxy or t == LocalName then + return true + end + return false + end, free_name = function(self, prefix, dont_put) prefix = prefix or "moon" local searching = true diff --git a/moonscript/compile.moon b/moonscript/compile.moon index c335b9e5..d1f0315d 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -241,6 +241,8 @@ class Block name = name\get_name self if NameProxy == mtype name @_names[name] = value + -- Check if a name is defined in the current or any enclosing scope + -- skip_exports: ignore names that have been exported using `export` has_name: (name, skip_exports) => return true if not skip_exports and @name_exported name @@ -251,6 +253,12 @@ class Block else yes + is_local: (node) => + t = mtype node + return @has_name(node, false) if t == "string" + return true if t == NameProxy or t == LocalName + false + free_name: (prefix, dont_put) => prefix = prefix or "moon" searching = true diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 42473539..afd40212 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -411,7 +411,7 @@ local Statement = Transformer({ end node = transformed or node if destructure.has_destructure(names) then - return destructure.split_assign(node) + return destructure.split_assign(self, node) end return node end, @@ -646,7 +646,7 @@ local Statement = Transformer({ if destructure.has_destructure(assign[2]) then local name = NameProxy("des") body = { - destructure.build_assign(assign[2][1], name), + destructure.build_assign(self, assign[2][1], name), build.group(node[3]) } return build["do"]({ @@ -725,7 +725,7 @@ local Statement = Transformer({ do local _with_0 = NameProxy("des") local proxy = _with_0 - insert(destructures, destructure.build_assign(name, proxy)) + insert(destructures, destructure.build_assign(self, name, proxy)) _accum_0[_len_0] = _with_0 end else diff --git a/moonscript/transform.moon b/moonscript/transform.moon index c8e9531b..5d3cbe93 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -189,8 +189,9 @@ Statement = Transformer { node = transformed or node + if destructure.has_destructure names - return destructure.split_assign node + return destructure.split_assign @, node -- print util.dump node node @@ -304,7 +305,7 @@ Statement = Transformer { name = NameProxy "des" body = { - destructure.build_assign assign[2][1], name + destructure.build_assign @, assign[2][1], name build.group node[3] } @@ -363,7 +364,7 @@ Statement = Transformer { node.names = for i, name in ipairs node.names if ntype(name) == "table" with proxy = NameProxy "des" - insert destructures, destructure.build_assign name, proxy + insert destructures, destructure.build_assign @, name, proxy else name diff --git a/moonscript/transform/destructure.lua b/moonscript/transform/destructure.lua index 3bc22ac3..0e534215 100644 --- a/moonscript/transform/destructure.lua +++ b/moonscript/transform/destructure.lua @@ -108,7 +108,7 @@ extract_assign_names = function(name, accum, prefix) return accum end local build_assign -build_assign = function(destruct_literal, receiver) +build_assign = function(scope, destruct_literal, receiver) local extracted_names = extract_assign_names(destruct_literal) local names = { } local values = { } @@ -118,7 +118,7 @@ build_assign = function(destruct_literal, receiver) values } local obj - if mtype(receiver) == NameProxy then + if scope:is_local(receiver) then obj = receiver else do @@ -139,7 +139,7 @@ build_assign = function(destruct_literal, receiver) for _index_0 = 1, #_list_0 do local tuple = _list_0[_index_0] insert(names, tuple[1]) - insert(values, obj:chain(unpack(tuple[2]))) + insert(values, NameProxy.chain(obj, unpack(tuple[2]))) end return build.group({ { @@ -150,7 +150,7 @@ build_assign = function(destruct_literal, receiver) }) end local split_assign -split_assign = function(assign) +split_assign = function(scope, assign) local names, values = unpack(assign, 2) local g = { } local total_names = #names @@ -182,7 +182,7 @@ split_assign = function(assign) end)() }) end - insert(g, build_assign(n, values[i])) + insert(g, build_assign(scope, n, values[i])) start = i + 1 end end diff --git a/moonscript/transform/destructure.moon b/moonscript/transform/destructure.moon index 4863729c..df20bbbf 100644 --- a/moonscript/transform/destructure.moon +++ b/moonscript/transform/destructure.moon @@ -47,7 +47,7 @@ extract_assign_names = (name, accum={}, prefix={}) -> accum -build_assign = (destruct_literal, receiver) -> +build_assign = (scope, destruct_literal, receiver) -> extracted_names = extract_assign_names destruct_literal names = {} @@ -55,7 +55,7 @@ build_assign = (destruct_literal, receiver) -> inner = {"assign", names, values} - obj = if mtype(receiver) == NameProxy + obj = if scope\is_local receiver receiver else with obj = NameProxy "obj" @@ -66,7 +66,8 @@ build_assign = (destruct_literal, receiver) -> for tuple in *extracted_names insert names, tuple[1] - insert values, obj\chain unpack tuple[2] + insert values, NameProxy.chain obj, unpack tuple[2] + -- insert values, obj\chain unpack tuple[2] build.group { {"declare", names} @@ -74,7 +75,7 @@ build_assign = (destruct_literal, receiver) -> } -- applies to destructuring to a assign node -split_assign = (assign) -> +split_assign = (scope, assign) -> names, values = unpack assign, 2 g = {} @@ -96,7 +97,7 @@ split_assign = (assign) -> values[i] } - insert g, build_assign n, values[i] + insert g, build_assign scope, n, values[i] start = i + 1 diff --git a/tests/inputs/destructure.moon b/tests/inputs/destructure.moon index e0118345..30a441e0 100644 --- a/tests/inputs/destructure.moon +++ b/tests/inputs/destructure.moon @@ -76,3 +76,21 @@ elseif {c,d} = thang else print "NO" + +-- + +do + z = "yeah" + {a,b,c} = z + +do + {a,b,c} = z + +(z) -> + {a,b,c} = z + +do + z = "oo" + (k) -> + {a,b,c} = z + diff --git a/tests/outputs/destructure.lua b/tests/outputs/destructure.lua index b2da4c3f..3540aa14 100644 --- a/tests/outputs/destructure.lua +++ b/tests/outputs/destructure.lua @@ -14,10 +14,7 @@ do hello, world = _obj_0.hello, _obj_0.world end local no, thing -do - local _obj_0 = world - no, thing = _obj_0.yes, _obj_0[1] -end +no, thing = world.yes, world[1] local d do local _obj_0 = yeah @@ -69,23 +66,11 @@ local futurists = { } } local name, street, city -do - local _obj_0 = futurists - name, street, city = _obj_0.poet.name, _obj_0.poet.address[1], _obj_0.poet.address[2] -end +name, street, city = futurists.poet.name, futurists.poet.address[1], futurists.poet.address[2] print(name, street, city) -do - local _obj_0 = x - self.world = _obj_0[1] -end -do - local _obj_0 = x - a.b, c.y, func().z = _obj_0[1], _obj_0[2], _obj_0[3] -end -do - local _obj_0 = x - self.world = _obj_0.world -end +self.world = x[1] +a.b, c.y, func().z = x[1], x[2], x[3] +self.world = x.world thing = { { 1, @@ -140,8 +125,27 @@ do c, d = _des_1[1], _des_1[2] print(c, d) else - return print("NO") + print("NO") end end end +end +do + local z = "yeah" + a, b, c = z[1], z[2], z[3] +end +do + do + local _obj_0 = z + a, b, c = _obj_0[1], _obj_0[2], _obj_0[3] + end +end +_ = function(z) + a, b, c = z[1], z[2], z[3] +end +do + local z = "oo" + return function(k) + a, b, c = z[1], z[2], z[3] + end end \ No newline at end of file From e1c2829d0e5a98251679c4f9f159e8af19e3a25e Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 6 Jun 2013 19:33:08 -0700 Subject: [PATCH 101/554] reorganize destructure tests --- tests/inputs/destructure.moon | 104 +++++++------- tests/outputs/destructure.lua | 256 +++++++++++++++++++--------------- 2 files changed, 200 insertions(+), 160 deletions(-) diff --git a/tests/inputs/destructure.moon b/tests/inputs/destructure.moon index 30a441e0..beb79d67 100644 --- a/tests/inputs/destructure.moon +++ b/tests/inputs/destructure.moon @@ -1,81 +1,85 @@ -{a, b} = hello +do + {a, b} = hello -{{a}, b, {c}} = hello + {{a}, b, {c}} = hello -{ :hello, :world } = value + { :hello, :world } = value -{ yes: no, thing } = world +do + { yes: no, thing } = world -{:a,:b,:c,:d} = yeah + {:a,:b,:c,:d} = yeah -{a} = one, two -{b}, c = one -{d}, e = one, two + {a} = one, two + {b}, c = one + {d}, e = one, two -x, {y} = one, two + x, {y} = one, two -xx, yy = 1, 2 -{yy, xx} = {xx, yy} + xx, yy = 1, 2 + {yy, xx} = {xx, yy} -{a, :b, c, :d, e, :f, g} = tbl + {a, :b, c, :d, e, :f, g} = tbl --- -futurists = - sculptor: "Umberto Boccioni" - painter: "Vladimir Burliuk" - poet: - name: "F.T. Marinetti" - address: { - "Via Roma 42R" - "Bellagio, Italy 22021" - } - -{poet: {:name, address: {street, city}}} = futurists - -print name, street, city +do + futurists = + sculptor: "Umberto Boccioni" + painter: "Vladimir Burliuk" + poet: + name: "F.T. Marinetti" + address: { + "Via Roma 42R" + "Bellagio, Italy 22021" + } + + {poet: {:name, address: {street, city}}} = futurists -- -{ @world } = x -{ a.b, c.y, func!.z } = x +do + { @world } = x + { a.b, c.y, func!.z } = x -{ world: @world } = x + { world: @world } = x -- -thing = {{1,2}, {3,4}} +do + thing = {{1,2}, {3,4}} -for {x,y} in *thing - print x,y + for {x,y} in *thing + print x,y -- -with {a,b} = thing - print a, b +do + with {a,b} = thing + print a, b -- -thing = nil -if {a} = thing - print a -else - print "nothing" - -thang = {1,2} -if {a,b} = thang - print a,b - -if {a,b} = thing - print a,b -elseif {c,d} = thang - print c,d -else - print "NO" - +do + thing = nil + if {a} = thing + print a + else + print "nothing" + + thang = {1,2} + if {a,b} = thang + print a,b + + if {a,b} = thing + print a,b + elseif {c,d} = thang + print c,d + else + print "NO" -- diff --git a/tests/outputs/destructure.lua b/tests/outputs/destructure.lua index 3540aa14..0ffc9ccb 100644 --- a/tests/outputs/destructure.lua +++ b/tests/outputs/destructure.lua @@ -1,151 +1,187 @@ -local a, b do - local _obj_0 = hello - a, b = _obj_0[1], _obj_0[2] -end -local c -do - local _obj_0 = hello - a, b, c = _obj_0[1][1], _obj_0[2], _obj_0[3][1] -end -local hello, world -do - local _obj_0 = value - hello, world = _obj_0.hello, _obj_0.world -end -local no, thing -no, thing = world.yes, world[1] -local d -do - local _obj_0 = yeah - a, b, c, d = _obj_0.a, _obj_0.b, _obj_0.c, _obj_0.d -end -do - local _obj_0 = one - a = _obj_0[1] -end -local _ = two -do - local _obj_0 = one - b = _obj_0[1] -end -c = nil -do - local _obj_0 = one - d = _obj_0[1] -end -local e = two -local x = one -local y -do - local _obj_0 = two - y = _obj_0[1] + local a, b + do + local _obj_0 = hello + a, b = _obj_0[1], _obj_0[2] + end + local c + do + local _obj_0 = hello + a, b, c = _obj_0[1][1], _obj_0[2], _obj_0[3][1] + end + local hello, world + do + local _obj_0 = value + hello, world = _obj_0.hello, _obj_0.world + end end -local xx, yy = 1, 2 do - local _obj_0 = { - xx, - yy - } - yy, xx = _obj_0[1], _obj_0[2] + local no, thing + do + local _obj_0 = world + no, thing = _obj_0.yes, _obj_0[1] + end + local a, b, c, d + do + local _obj_0 = yeah + a, b, c, d = _obj_0.a, _obj_0.b, _obj_0.c, _obj_0.d + end + do + local _obj_0 = one + a = _obj_0[1] + end + local _ = two + do + local _obj_0 = one + b = _obj_0[1] + end + c = nil + do + local _obj_0 = one + d = _obj_0[1] + end + local e = two + local x = one + local y + do + local _obj_0 = two + y = _obj_0[1] + end + local xx, yy = 1, 2 + do + local _obj_0 = { + xx, + yy + } + yy, xx = _obj_0[1], _obj_0[2] + end + local f, g + do + local _obj_0 = tbl + a, b, c, d, e, f, g = _obj_0[1], _obj_0.b, _obj_0[2], _obj_0.d, _obj_0[3], _obj_0.f, _obj_0[4] + end end -local f, g do - local _obj_0 = tbl - a, b, c, d, e, f, g = _obj_0[1], _obj_0.b, _obj_0[2], _obj_0.d, _obj_0[3], _obj_0.f, _obj_0[4] -end -local futurists = { - sculptor = "Umberto Boccioni", - painter = "Vladimir Burliuk", - poet = { - name = "F.T. Marinetti", - address = { - "Via Roma 42R", - "Bellagio, Italy 22021" + local futurists = { + sculptor = "Umberto Boccioni", + painter = "Vladimir Burliuk", + poet = { + name = "F.T. Marinetti", + address = { + "Via Roma 42R", + "Bellagio, Italy 22021" + } } } -} -local name, street, city -name, street, city = futurists.poet.name, futurists.poet.address[1], futurists.poet.address[2] -print(name, street, city) -self.world = x[1] -a.b, c.y, func().z = x[1], x[2], x[3] -self.world = x.world -thing = { - { - 1, - 2 - }, - { - 3, - 4 - } -} -local _list_0 = thing -for _index_0 = 1, #_list_0 do - local _des_0 = _list_0[_index_0] - x, y = _des_0[1], _des_0[2] - print(x, y) + local name, street, city + name, street, city = futurists.poet.name, futurists.poet.address[1], futurists.poet.address[2] end do - local _with_0 = thing - a, b = _with_0[1], _with_0[2] - print(a, b) + do + local _obj_0 = x + self.world = _obj_0[1] + end + do + local _obj_0 = x + a.b, c.y, func().z = _obj_0[1], _obj_0[2], _obj_0[3] + end + do + local _obj_0 = x + self.world = _obj_0.world + end end -thing = nil do - local _des_0 = thing - if _des_0 then - a = _des_0[1] - print(a) - else - print("nothing") + local thing = { + { + 1, + 2 + }, + { + 3, + 4 + } + } + local _list_0 = thing + for _index_0 = 1, #_list_0 do + local _des_0 = _list_0[_index_0] + local x, y + x, y = _des_0[1], _des_0[2] + print(x, y) end end -local thang = { - 1, - 2 -} do - local _des_0 = thang - if _des_0 then - a, b = _des_0[1], _des_0[2] + do + local _with_0 = thing + local a, b + a, b = _with_0[1], _with_0[2] print(a, b) end end do - local _des_0 = thing - if _des_0 then - a, b = _des_0[1], _des_0[2] - print(a, b) - else - do - local _des_1 = thang - if _des_1 then - c, d = _des_1[1], _des_1[2] - print(c, d) - else - print("NO") + local thing = nil + do + local _des_0 = thing + if _des_0 then + local a + a = _des_0[1] + print(a) + else + print("nothing") + end + end + local thang = { + 1, + 2 + } + do + local _des_0 = thang + if _des_0 then + local a, b + a, b = _des_0[1], _des_0[2] + print(a, b) + end + end + do + local _des_0 = thing + if _des_0 then + local a, b + a, b = _des_0[1], _des_0[2] + print(a, b) + else + do + local _des_1 = thang + if _des_1 then + local c, d + c, d = _des_1[1], _des_1[2] + print(c, d) + else + print("NO") + end end end end end do local z = "yeah" + local a, b, c a, b, c = z[1], z[2], z[3] end do + local a, b, c do local _obj_0 = z a, b, c = _obj_0[1], _obj_0[2], _obj_0[3] end end +local _ _ = function(z) + local a, b, c a, b, c = z[1], z[2], z[3] end do local z = "oo" return function(k) + local a, b, c a, b, c = z[1], z[2], z[3] end end \ No newline at end of file From e705656b043c1464493e988ca61c6f7f887f3326 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 6 Jun 2013 19:33:46 -0700 Subject: [PATCH 102/554] rebuild --- moonscript/compile.lua | 5 +---- moonscript/transform.lua | 15 +++------------ 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/moonscript/compile.lua b/moonscript/compile.lua index 1792ac5d..e674f746 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -593,10 +593,7 @@ do error("deprecated stms call, use transformer") end local current_stms, current_stm_i - do - local _obj_0 = self - current_stms, current_stm_i = _obj_0.current_stms, _obj_0.current_stm_i - end + current_stms, current_stm_i = self.current_stms, self.current_stm_i self.current_stms = stms for i = 1, #stms do self.current_stm_i = i diff --git a/moonscript/transform.lua b/moonscript/transform.lua index afd40212..c1bf9b72 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -295,10 +295,7 @@ construct_comprehension = function(inner, clauses) 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 + _, name, bounds = clause[1], clause[2], clause[3] current_stms = { "for", name, @@ -307,10 +304,7 @@ construct_comprehension = function(inner, clauses) } elseif "foreach" == _exp_0 then local names, iter - do - local _obj_0 = clause - _, names, iter = _obj_0[1], _obj_0[2], _obj_0[3] - end + _, names, iter = clause[1], clause[2], clause[3] current_stms = { "foreach", names, @@ -321,10 +315,7 @@ construct_comprehension = function(inner, clauses) } elseif "when" == _exp_0 then local cond - do - local _obj_0 = clause - _, cond = _obj_0[1], _obj_0[2] - end + _, cond = clause[1], clause[2] current_stms = { "if", cond, From abbf46ac373f1e3b0d8f13b015c27d4edb04b9b4 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 7 Jun 2013 23:14:08 -0700 Subject: [PATCH 103/554] move test to spec --- Makefile | 2 +- README.md | 9 +- {tests => spec}/error_inputs/first.moon | 0 {tests => spec}/error_inputs/second.moon | 0 {tests => spec}/error_inputs/third.moon | 0 {tests => spec}/inputs/assign.moon | 0 {tests => spec}/inputs/bubbling.moon | 0 {tests => spec}/inputs/class.moon | 0 {tests => spec}/inputs/comprehension.moon | 0 {tests => spec}/inputs/cond.moon | 0 {tests => spec}/inputs/destructure.moon | 0 {tests => spec}/inputs/do.moon | 0 {tests => spec}/inputs/export.moon | 0 {tests => spec}/inputs/funcs.moon | 0 {tests => spec}/inputs/import.moon | 0 {tests => spec}/inputs/lists.moon | 0 {tests => spec}/inputs/literals.moon | 0 {tests => spec}/inputs/local.moon | 0 {tests => spec}/inputs/loops.moon | 0 {tests => spec}/inputs/string.moon | 0 {tests => spec}/inputs/stub.moon | 0 {tests => spec}/inputs/switch.moon | 0 {tests => spec}/inputs/syntax.moon | 0 {tests => spec}/inputs/tables.moon | 0 {tests => spec}/inputs/using.moon | 0 {tests => spec}/inputs/whitespace.moon | 0 {tests => spec}/inputs/with.moon | 0 test2.moon => spec/lang_spec.moon | 5 +- {tests => spec}/outputs/assign.lua | 0 {tests => spec}/outputs/bubbling.lua | 0 {tests => spec}/outputs/class.lua | 0 {tests => spec}/outputs/comprehension.lua | 0 {tests => spec}/outputs/cond.lua | 0 {tests => spec}/outputs/destructure.lua | 0 {tests => spec}/outputs/do.lua | 0 {tests => spec}/outputs/export.lua | 0 {tests => spec}/outputs/funcs.lua | 0 {tests => spec}/outputs/import.lua | 0 {tests => spec}/outputs/lists.lua | 0 {tests => spec}/outputs/literals.lua | 0 {tests => spec}/outputs/local.lua | 0 {tests => spec}/outputs/loops.lua | 0 {tests => spec}/outputs/string.lua | 0 {tests => spec}/outputs/stub.lua | 0 {tests => spec}/outputs/switch.lua | 0 {tests => spec}/outputs/syntax.lua | 0 {tests => spec}/outputs/tables.lua | 0 {tests => spec}/outputs/using.lua | 0 {tests => spec}/outputs/whitespace.lua | 0 {tests => spec}/outputs/with.lua | 0 test.lua | 192 ---------------------- 51 files changed, 8 insertions(+), 200 deletions(-) rename {tests => spec}/error_inputs/first.moon (100%) rename {tests => spec}/error_inputs/second.moon (100%) rename {tests => spec}/error_inputs/third.moon (100%) rename {tests => spec}/inputs/assign.moon (100%) rename {tests => spec}/inputs/bubbling.moon (100%) rename {tests => spec}/inputs/class.moon (100%) rename {tests => spec}/inputs/comprehension.moon (100%) rename {tests => spec}/inputs/cond.moon (100%) rename {tests => spec}/inputs/destructure.moon (100%) rename {tests => spec}/inputs/do.moon (100%) rename {tests => spec}/inputs/export.moon (100%) rename {tests => spec}/inputs/funcs.moon (100%) rename {tests => spec}/inputs/import.moon (100%) rename {tests => spec}/inputs/lists.moon (100%) rename {tests => spec}/inputs/literals.moon (100%) rename {tests => spec}/inputs/local.moon (100%) rename {tests => spec}/inputs/loops.moon (100%) rename {tests => spec}/inputs/string.moon (100%) rename {tests => spec}/inputs/stub.moon (100%) rename {tests => spec}/inputs/switch.moon (100%) rename {tests => spec}/inputs/syntax.moon (100%) rename {tests => spec}/inputs/tables.moon (100%) rename {tests => spec}/inputs/using.moon (100%) rename {tests => spec}/inputs/whitespace.moon (100%) rename {tests => spec}/inputs/with.moon (100%) rename test2.moon => spec/lang_spec.moon (98%) rename {tests => spec}/outputs/assign.lua (100%) rename {tests => spec}/outputs/bubbling.lua (100%) rename {tests => spec}/outputs/class.lua (100%) rename {tests => spec}/outputs/comprehension.lua (100%) rename {tests => spec}/outputs/cond.lua (100%) rename {tests => spec}/outputs/destructure.lua (100%) rename {tests => spec}/outputs/do.lua (100%) rename {tests => spec}/outputs/export.lua (100%) rename {tests => spec}/outputs/funcs.lua (100%) rename {tests => spec}/outputs/import.lua (100%) rename {tests => spec}/outputs/lists.lua (100%) rename {tests => spec}/outputs/literals.lua (100%) rename {tests => spec}/outputs/local.lua (100%) rename {tests => spec}/outputs/loops.lua (100%) rename {tests => spec}/outputs/string.lua (100%) rename {tests => spec}/outputs/stub.lua (100%) rename {tests => spec}/outputs/switch.lua (100%) rename {tests => spec}/outputs/syntax.lua (100%) rename {tests => spec}/outputs/tables.lua (100%) rename {tests => spec}/outputs/using.lua (100%) rename {tests => spec}/outputs/whitespace.lua (100%) rename {tests => spec}/outputs/with.lua (100%) delete mode 100755 test.lua diff --git a/Makefile b/Makefile index d90631dd..2f13dfea 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ test:: - moonc test2.moon && TIME=1 busted test2.lua + busted -p "_spec.moon$$" local: luarocks make --local moonscript-dev-1.rockspec diff --git a/README.md b/README.md index de9f83d3..db9203c5 100644 --- a/README.md +++ b/README.md @@ -8,14 +8,15 @@ See . Online demo/compiler at . - ## Running Tests -Tests are written in MoonScript using [Busted](http://olivinelabs.com/busted/). -In order to run the tests you must compile the test runner file before executing. +Tests are written in MoonScript and use [Busted](http://olivinelabs.com/busted/). +In order to run the tests you must have MoonScript installed. + +To run tests, execute from the root directory: ```bash -moonc test2.moon && busted test2.lua +busted ``` ## License (MIT) diff --git a/tests/error_inputs/first.moon b/spec/error_inputs/first.moon similarity index 100% rename from tests/error_inputs/first.moon rename to spec/error_inputs/first.moon diff --git a/tests/error_inputs/second.moon b/spec/error_inputs/second.moon similarity index 100% rename from tests/error_inputs/second.moon rename to spec/error_inputs/second.moon diff --git a/tests/error_inputs/third.moon b/spec/error_inputs/third.moon similarity index 100% rename from tests/error_inputs/third.moon rename to spec/error_inputs/third.moon diff --git a/tests/inputs/assign.moon b/spec/inputs/assign.moon similarity index 100% rename from tests/inputs/assign.moon rename to spec/inputs/assign.moon diff --git a/tests/inputs/bubbling.moon b/spec/inputs/bubbling.moon similarity index 100% rename from tests/inputs/bubbling.moon rename to spec/inputs/bubbling.moon diff --git a/tests/inputs/class.moon b/spec/inputs/class.moon similarity index 100% rename from tests/inputs/class.moon rename to spec/inputs/class.moon diff --git a/tests/inputs/comprehension.moon b/spec/inputs/comprehension.moon similarity index 100% rename from tests/inputs/comprehension.moon rename to spec/inputs/comprehension.moon diff --git a/tests/inputs/cond.moon b/spec/inputs/cond.moon similarity index 100% rename from tests/inputs/cond.moon rename to spec/inputs/cond.moon diff --git a/tests/inputs/destructure.moon b/spec/inputs/destructure.moon similarity index 100% rename from tests/inputs/destructure.moon rename to spec/inputs/destructure.moon diff --git a/tests/inputs/do.moon b/spec/inputs/do.moon similarity index 100% rename from tests/inputs/do.moon rename to spec/inputs/do.moon diff --git a/tests/inputs/export.moon b/spec/inputs/export.moon similarity index 100% rename from tests/inputs/export.moon rename to spec/inputs/export.moon diff --git a/tests/inputs/funcs.moon b/spec/inputs/funcs.moon similarity index 100% rename from tests/inputs/funcs.moon rename to spec/inputs/funcs.moon diff --git a/tests/inputs/import.moon b/spec/inputs/import.moon similarity index 100% rename from tests/inputs/import.moon rename to spec/inputs/import.moon diff --git a/tests/inputs/lists.moon b/spec/inputs/lists.moon similarity index 100% rename from tests/inputs/lists.moon rename to spec/inputs/lists.moon diff --git a/tests/inputs/literals.moon b/spec/inputs/literals.moon similarity index 100% rename from tests/inputs/literals.moon rename to spec/inputs/literals.moon diff --git a/tests/inputs/local.moon b/spec/inputs/local.moon similarity index 100% rename from tests/inputs/local.moon rename to spec/inputs/local.moon diff --git a/tests/inputs/loops.moon b/spec/inputs/loops.moon similarity index 100% rename from tests/inputs/loops.moon rename to spec/inputs/loops.moon diff --git a/tests/inputs/string.moon b/spec/inputs/string.moon similarity index 100% rename from tests/inputs/string.moon rename to spec/inputs/string.moon diff --git a/tests/inputs/stub.moon b/spec/inputs/stub.moon similarity index 100% rename from tests/inputs/stub.moon rename to spec/inputs/stub.moon diff --git a/tests/inputs/switch.moon b/spec/inputs/switch.moon similarity index 100% rename from tests/inputs/switch.moon rename to spec/inputs/switch.moon diff --git a/tests/inputs/syntax.moon b/spec/inputs/syntax.moon similarity index 100% rename from tests/inputs/syntax.moon rename to spec/inputs/syntax.moon diff --git a/tests/inputs/tables.moon b/spec/inputs/tables.moon similarity index 100% rename from tests/inputs/tables.moon rename to spec/inputs/tables.moon diff --git a/tests/inputs/using.moon b/spec/inputs/using.moon similarity index 100% rename from tests/inputs/using.moon rename to spec/inputs/using.moon diff --git a/tests/inputs/whitespace.moon b/spec/inputs/whitespace.moon similarity index 100% rename from tests/inputs/whitespace.moon rename to spec/inputs/whitespace.moon diff --git a/tests/inputs/with.moon b/spec/inputs/with.moon similarity index 100% rename from tests/inputs/with.moon rename to spec/inputs/with.moon diff --git a/test2.moon b/spec/lang_spec.moon similarity index 98% rename from test2.moon rename to spec/lang_spec.moon index 49eec864..f0c72fd5 100644 --- a/test2.moon +++ b/spec/lang_spec.moon @@ -1,4 +1,3 @@ - lfs = require "lfs" parse = require "moonscript.parse" @@ -10,8 +9,8 @@ pattern = ... import unpack from util options = { - in_dir: "tests/inputs", - out_dir: "tests/outputs", + in_dir: "spec/inputs", + out_dir: "spec/outputs", input_pattern: "(.*)%.moon$", output_ext: ".lua" diff --git a/tests/outputs/assign.lua b/spec/outputs/assign.lua similarity index 100% rename from tests/outputs/assign.lua rename to spec/outputs/assign.lua diff --git a/tests/outputs/bubbling.lua b/spec/outputs/bubbling.lua similarity index 100% rename from tests/outputs/bubbling.lua rename to spec/outputs/bubbling.lua diff --git a/tests/outputs/class.lua b/spec/outputs/class.lua similarity index 100% rename from tests/outputs/class.lua rename to spec/outputs/class.lua diff --git a/tests/outputs/comprehension.lua b/spec/outputs/comprehension.lua similarity index 100% rename from tests/outputs/comprehension.lua rename to spec/outputs/comprehension.lua diff --git a/tests/outputs/cond.lua b/spec/outputs/cond.lua similarity index 100% rename from tests/outputs/cond.lua rename to spec/outputs/cond.lua diff --git a/tests/outputs/destructure.lua b/spec/outputs/destructure.lua similarity index 100% rename from tests/outputs/destructure.lua rename to spec/outputs/destructure.lua diff --git a/tests/outputs/do.lua b/spec/outputs/do.lua similarity index 100% rename from tests/outputs/do.lua rename to spec/outputs/do.lua diff --git a/tests/outputs/export.lua b/spec/outputs/export.lua similarity index 100% rename from tests/outputs/export.lua rename to spec/outputs/export.lua diff --git a/tests/outputs/funcs.lua b/spec/outputs/funcs.lua similarity index 100% rename from tests/outputs/funcs.lua rename to spec/outputs/funcs.lua diff --git a/tests/outputs/import.lua b/spec/outputs/import.lua similarity index 100% rename from tests/outputs/import.lua rename to spec/outputs/import.lua diff --git a/tests/outputs/lists.lua b/spec/outputs/lists.lua similarity index 100% rename from tests/outputs/lists.lua rename to spec/outputs/lists.lua diff --git a/tests/outputs/literals.lua b/spec/outputs/literals.lua similarity index 100% rename from tests/outputs/literals.lua rename to spec/outputs/literals.lua diff --git a/tests/outputs/local.lua b/spec/outputs/local.lua similarity index 100% rename from tests/outputs/local.lua rename to spec/outputs/local.lua diff --git a/tests/outputs/loops.lua b/spec/outputs/loops.lua similarity index 100% rename from tests/outputs/loops.lua rename to spec/outputs/loops.lua diff --git a/tests/outputs/string.lua b/spec/outputs/string.lua similarity index 100% rename from tests/outputs/string.lua rename to spec/outputs/string.lua diff --git a/tests/outputs/stub.lua b/spec/outputs/stub.lua similarity index 100% rename from tests/outputs/stub.lua rename to spec/outputs/stub.lua diff --git a/tests/outputs/switch.lua b/spec/outputs/switch.lua similarity index 100% rename from tests/outputs/switch.lua rename to spec/outputs/switch.lua diff --git a/tests/outputs/syntax.lua b/spec/outputs/syntax.lua similarity index 100% rename from tests/outputs/syntax.lua rename to spec/outputs/syntax.lua diff --git a/tests/outputs/tables.lua b/spec/outputs/tables.lua similarity index 100% rename from tests/outputs/tables.lua rename to spec/outputs/tables.lua diff --git a/tests/outputs/using.lua b/spec/outputs/using.lua similarity index 100% rename from tests/outputs/using.lua rename to spec/outputs/using.lua diff --git a/tests/outputs/whitespace.lua b/spec/outputs/whitespace.lua similarity index 100% rename from tests/outputs/whitespace.lua rename to spec/outputs/whitespace.lua diff --git a/tests/outputs/with.lua b/spec/outputs/with.lua similarity index 100% rename from tests/outputs/with.lua rename to spec/outputs/with.lua diff --git a/test.lua b/test.lua deleted file mode 100755 index 0b95e35b..00000000 --- a/test.lua +++ /dev/null @@ -1,192 +0,0 @@ -#!/usr/bin/env lua - -require "lfs" -require "alt_getopt" - -local gettime = nil - -pcall(function() - require "socket" - gettime = socket.gettime -end) - -parse = require "moonscript.parse" -compile = require "moonscript.compile" - -local opts, ind = alt_getopt.get_opts(arg, "qd:", { }) - -local argv = {} -for i = ind, #arg do table.insert(argv, arg[i]) end - -local action = table.remove(argv, 1) or "run" - -local diff_tool = opts.d or "diff" -local quiet = opts.q - -local opts = { - in_dir = "tests/inputs", - out_dir = "tests/outputs", - input_pattern = "(.*)%.moon$", - output_ext = ".lua" -} - -local total_time = { - parse = 0, - compile = 0 -} - -local function format_time(sec) - return ("%.3fms"):format(sec*1000) -end - -local function diff(a_fname, b_fname) - return io.popen(diff_tool.." ".. a_fname.." "..b_fname, "r"):read("*a") -end - -local function input_name(name) return opts.in_dir.."/".. name end -local function output_name(name) - return opts.out_dir.."/"..name:match(opts.input_pattern)..opts.output_ext -end - -local function run_file(name, benchmark) - name = input_name(name) - file_str = io.open(name):read("*a") - - local start_parse - if benchmark then start_parse = gettime() end - - local tree, err = parse.string(file_str) - - local parse_time = 0 - if benchmark then parse_time = gettime() - start_parse end - - if not tree then - error("Parse error in "..name.."\n"..err) - end - - local start_compile - if benchmark then start_compile = gettime() end - - local code, err, pos = compile.tree(tree) - if not code then - print() - print(("Failed to compile: %s"):format(name)) - print(compile.format_error(err, pos, file_str)) - os.exit() - end - - -- local success, code = pcall(compile.tree, tree) - -- if not success then - -- error("Compile error in"..name..":\n"..code) - -- end - - if benchmark then - local compile_time = gettime() - start_compile - return code, parse_time, compile_time - end - - return code -end - -local function inputs(pattern) - return coroutine.wrap(function() - for file in lfs.dir(opts.in_dir) do - local body = file:match(opts.input_pattern) - if body then - if not pattern or body:match(pattern) then - coroutine.yield(file) - end - end - end - end) -end - -local actions = { - build = function(pattern) - for file in inputs(pattern) do - local out_fname = output_name(file) - print("Building: ", file, out_fname) - local result = run_file(file) - if result then - io.open(out_fname, "w"):write(result) - end - end - end, - run = function(pattern) - local failed = false - local tests_run, result = 0 - for file in inputs(pattern) do - tests_run = tests_run + 1 - local correct_fname = output_name(file) - result, parse_time, compile_time = run_file(file, gettime) - local handle = io.open(correct_fname) - - if not handle then - print("Test not built yet:", correct_fname) - else - local correct = handle:read("*a") - if result ~= correct then - print("Test", file, "failed") - local tmp_name = os.tmpname() - local tmp = io.open(tmp_name, "w") - tmp:write(result) - tmp:close() - - if not quiet then - print(diff(correct_fname, tmp_name)) - end - os.remove(tmp_name) - -- break - else - if parse_time then - total_time.parse = total_time.parse + parse_time - total_time.compile = total_time.compile + compile_time - - parse_time = format_time(parse_time) - compile_time = format_time(compile_time) - print("Test", file, "passed", "", - ("p: %s, c: %s"):format(parse_time, compile_time)) - else - print("Test", file, "passed") - end - end - end - end - - if gettime then - print"" - print"total:" - print(" parse time", format_time(total_time.parse)) - print(" compile time", format_time(total_time.compile)) - end - - - if tests_run == 0 then - if not pattern then - print("No tests found") - else - print("No tests matching pattern:", pattern) - end - elseif tests_run == 1 then - -- print(result) - end - end, - list = function(pattern) - local count = 0 - for file in inputs(pattern) do - count = count + 1 - print(file) - end - if count > 0 then print("") end - print("Count:", count) - end -} - -local fn = actions[action] -if fn then - fn(unpack(argv)) -else - print("Unknown action:", action) -end - - From e65ac4946daa6808170a3747965d070ab2488066 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 7 Jun 2013 23:33:47 -0700 Subject: [PATCH 104/554] tweak makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 2f13dfea..30b30229 100644 --- a/Makefile +++ b/Makefile @@ -16,4 +16,4 @@ compile_global: moonc moon/ moonscript/ watch: - moonc -w moon/ moonscript/ + moonc moon/ moonscript/ && moonc -w moon/ moonscript/ From 2f4066d9bbeedb2400a15b7c6d735ba892ece016 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 7 Jun 2013 23:34:03 -0700 Subject: [PATCH 105/554] update moon library to not use module --- moon/all.lua | 8 +++++--- moon/all.moon | 12 +++++------- moon/init.lua | 21 +++++++++++++++++---- moon/init.moon | 11 +++++------ 4 files changed, 32 insertions(+), 20 deletions(-) diff --git a/moon/all.lua b/moon/all.lua index fd23b7e9..945576d1 100644 --- a/moon/all.lua +++ b/moon/all.lua @@ -1,3 +1,5 @@ -moon = moon or { } -moon.inject = true -return require("moon.init") +local moon = require("moon") +for k, v in pairs(moon) do + _G[k] = v +end +return moon diff --git a/moon/all.moon b/moon/all.moon index 86b33547..cb773c70 100644 --- a/moon/all.moon +++ b/moon/all.moon @@ -1,8 +1,6 @@ - --- insert all moon library functions into requiring scope - -export moon -moon = moon or {} -moon.inject = true -require "moon.init" +-- install moon into global scope +moon = require "moon" +for k,v in pairs moon + _G[k] = v +moon diff --git a/moon/init.lua b/moon/init.lua index 5cf4be88..f05fe074 100644 --- a/moon/init.lua +++ b/moon/init.lua @@ -1,11 +1,9 @@ -if not moon or not moon.inject then - module("moon", package.seeall) -end local util = require("moonscript.util") local lua = { debug = debug, type = type } +local dump, p, is_object, type, debug, run_with_scope, bind_methods, defaultbl, extend, copy, mixin, mixin_object, mixin_table, fold dump = util.dump p = function(...) return print(dump(...)) @@ -161,4 +159,19 @@ fold = function(items, fn) return items[1] end end -return nil +return { + dump = dump, + p = p, + is_object = is_object, + type = type, + debug = debug, + run_with_scope = run_with_scope, + bind_methods = bind_methods, + defaultbl = defaultbl, + extend = extend, + copy = copy, + mixin = mixin, + mixin_object = mixin_object, + mixin_table = mixin_table, + fold = fold +} diff --git a/moon/init.moon b/moon/init.moon index 22cce0c7..7fd6c590 100644 --- a/moon/init.moon +++ b/moon/init.moon @@ -1,12 +1,8 @@ -if not moon or not moon.inject - module "moon", package.seeall - util = require "moonscript.util" - lua = { :debug, :type } -export * +local * dump = util.dump @@ -134,4 +130,7 @@ fold = (items, fn)-> else items[1] -nil +{ + :dump, :p, :is_object, :type, :debug, :run_with_scope, :bind_methods, + :defaultbl, :extend, :copy, :mixin, :mixin_object, :mixin_table, :fold +} From fcf36aeb8c5477677026626bb572db7f3185d9d4 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 8 Jun 2013 00:06:56 -0700 Subject: [PATCH 106/554] fix moon.mixin, fixes #99 --- moon/init.lua | 3 +-- moon/init.moon | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/moon/init.lua b/moon/init.lua index f05fe074..91d20e24 100644 --- a/moon/init.lua +++ b/moon/init.lua @@ -117,8 +117,7 @@ copy = function(self) end)() end mixin = function(self, cls, ...) - local meta = getmetatable(cls) - for key, val in pairs(meta.__index) do + for key, val in pairs(cls.__base) do if not key:match("^__") then self[key] = val end diff --git a/moon/init.moon b/moon/init.moon index 7fd6c590..ef07bbaf 100644 --- a/moon/init.moon +++ b/moon/init.moon @@ -100,8 +100,7 @@ copy = => -- mixin class properties into self, call new mixin = (cls, ...) => - meta = getmetatable cls - for key, val in pairs meta.__index + for key, val in pairs cls.__base self[key] = val if not key\match"^__" cls.__init self, ... From 8e2a4daa4a5e445d8087c20848e7e0381f8f043c Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 8 Jun 2013 00:13:03 -0700 Subject: [PATCH 107/554] specs for moon lib --- docs/standard_lib.md | 2 +- spec/moon_spec.moon | 116 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 spec/moon_spec.moon diff --git a/docs/standard_lib.md b/docs/standard_lib.md index 2138f5a5..566ffe7c 100644 --- a/docs/standard_lib.md +++ b/docs/standard_lib.md @@ -166,7 +166,7 @@ overwritten. ### `mixin_object(obj, other_obj, method_names)` -Inserts into `obj` methods from `other_obj` whose names are listen in +Inserts into `obj` methods from `other_obj` whose names are listed in `method_names`. The inserted methods are bound methods that will run with `other_obj` as the receiver. diff --git a/spec/moon_spec.moon b/spec/moon_spec.moon new file mode 100644 index 00000000..145b5ee1 --- /dev/null +++ b/spec/moon_spec.moon @@ -0,0 +1,116 @@ +-- test moon library + +moon = require "moon" + +describe "moon", -> + it "should determine correct type", -> + class Test + + things = { + Test, Test!, 1, true, nil, "hello" + } + + types = [moon.type t for t in *things] + assert.same types, { Test, Test, "number", "boolean", "nil", "string" } + + it "should get upvalue", -> + fn = do + hello = "world" + -> hello + + assert.same moon.debug.upvalue(fn, "hello"), "world" + + it "should set upvalue", -> + fn = do + hello = "world" + -> hello + + moon.debug.upvalue fn, "hello", "foobar" + assert.same fn!, "foobar" + + it "should run with scope", -> + scope = hello: -> + spy.on scope, "hello" + moon.run_with_scope (-> hello!), scope + + assert.spy(scope.hello).was.called! + + + it "should have access to old environment", -> + scope = {} + res = moon.run_with_scope (-> math), scope + + assert.same res, math + + it "should created bound proxy", -> + class Hello + state: 10 + method: (val) => "the state: #{@state}, the val: #{val}" + + hello = Hello! + bound = moon.bind_methods hello + + assert.same bound.method("xxx"), "the state: 10, the val: xxx" + + it "should create defaulted table", -> + fib = moon.defaultbl {[0]: 0, [1]: 1}, (i) => self[i - 1] + self[i - 2] + fib[7] + + assert.same fib, { [0]: 0, 1, 1, 2, 3, 5, 8, 13 } + + it "should extend", -> + t1 = { hello: "world's", cool: "shortest" } + t2 = { cool: "boots", cowboy: "hat" } + + out = moon.extend t1, t2 + + assert.same { out.hello, out.cool, out.cowboy }, { "world's", "shortest", "hat"} + + it "should make a copy", -> + x = { "hello", yeah: "man" } + y = moon.copy x + + x[1] = "yikes" + x.yeah = "woman" + + assert.same y, { "hello", yeah: "man" } + + + it "should mixin", -> + class TestModule + new: (@var) => + show_var: => "var is: #{@var}" + + class Second + new: => + moon.mixin self, TestModule, "hi" + + obj = Second! + + assert.same obj\show_var!, "var is: hi" + + it "should mixin object", -> + class First + val: 10 + get_val: => "the val: #{@val}" + + class Second + val: 20 + new: => + moon.mixin_object @, First!, { "get_val" } + + obj = Second! + assert.same obj\get_val!, "the val: 10" + + it "should mixin table", -> + a = { hello: "world", cat: "dog" } + b = { cat: "mouse", foo: "bar" } + moon.mixin_table a, b + + assert.same a, { hello: "world", cat: "mouse", foo: "bar"} + + it "should fold", -> + numbers = {4,3,5,6,7,2,3} + sum = moon.fold numbers, (a,b) -> a + b + + assert.same sum, 30 From d42bbff85338624a45a9b07e6878d00cf8ac7307 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 8 Jun 2013 00:33:02 -0700 Subject: [PATCH 108/554] error rewriting spec --- moonscript/errors.lua | 3 ++- moonscript/errors.moon | 2 +- spec/error_inputs/first.moon | 2 ++ spec/error_inputs/second.moon | 1 + spec/error_inputs/third.moon | 2 ++ spec/error_rewriting_spec.moon | 30 ++++++++++++++++++++++++++++++ 6 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 spec/error_rewriting_spec.moon diff --git a/moonscript/errors.lua b/moonscript/errors.lua index 58d1d9c1..af3c98ed 100644 --- a/moonscript/errors.lua +++ b/moonscript/errors.lua @@ -107,5 +107,6 @@ end return { rewrite_traceback = rewrite_traceback, truncate_traceback = truncate_traceback, - user_error = user_error + user_error = user_error, + reverse_line_number = reverse_line_number } diff --git a/moonscript/errors.moon b/moonscript/errors.moon index 3bba4476..a5bd94e8 100644 --- a/moonscript/errors.moon +++ b/moonscript/errors.moon @@ -84,5 +84,5 @@ rewrite_traceback = (text, err) -> }, "\n" -{ :rewrite_traceback, :truncate_traceback, :user_error } +{ :rewrite_traceback, :truncate_traceback, :user_error, :reverse_line_number } diff --git a/spec/error_inputs/first.moon b/spec/error_inputs/first.moon index 15afa9e3..c8d45fa4 100644 --- a/spec/error_inputs/first.moon +++ b/spec/error_inputs/first.moon @@ -1,6 +1,8 @@ hello_world = false +print = -> + if hello_world print "sackman" x = 5 + 5 diff --git a/spec/error_inputs/second.moon b/spec/error_inputs/second.moon index 053dcca3..d9b7e689 100644 --- a/spec/error_inputs/second.moon +++ b/spec/error_inputs/second.moon @@ -1,4 +1,5 @@ +print = -> if false true diff --git a/spec/error_inputs/third.moon b/spec/error_inputs/third.moon index 08ef1d7d..b3c1e2e9 100644 --- a/spec/error_inputs/third.moon +++ b/spec/error_inputs/third.moon @@ -1,4 +1,6 @@ +print = -> + if (-> print "hello world" print "who is this") diff --git a/spec/error_rewriting_spec.moon b/spec/error_rewriting_spec.moon new file mode 100644 index 00000000..d2f55c98 --- /dev/null +++ b/spec/error_rewriting_spec.moon @@ -0,0 +1,30 @@ + +moonscript = require "moonscript.base" +errors = require "moonscript.errors" +util = require "moonscript.util" + +get_rewritten_line_no = (fname) -> + fname = "spec/error_inputs/#{fname}.moon" + chunk = moonscript.loadfile fname + + success, err = pcall chunk + error "`#{fname}` is supposed to have runtime error!" if success + + source = tonumber err\match "]:(%d+)" + + line_table = require("moonscript.line_tables")[fname] + errors.reverse_line_number fname, line_table, source, {} + + +-- TODO: check entire stack trace +describe "error rewriting", -> + tests = { + "first": 24 + "second": 16 + "third": 11 + } + + for name, expected_no in pairs tests + it "should rewrite line number", -> + assert.same get_rewritten_line_no(name), expected_no + From 2b4ff609433bc0bf3cc125707f2aa742d4f1db10 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 8 Jun 2013 00:33:32 -0700 Subject: [PATCH 109/554] todo -> thoughts --- todo => thoughts | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename todo => thoughts (100%) diff --git a/todo b/thoughts similarity index 100% rename from todo rename to thoughts From aa2d411693628811bb59a6155277cdb72179ac96 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Mon, 10 Jun 2013 13:10:56 -0700 Subject: [PATCH 110/554] don't evaluate apply to last until the node is transormed --- moonscript/compile/statement.lua | 3 ++- moonscript/compile/statement.moon | 2 ++ moonscript/transform.lua | 15 +++++++++++++-- moonscript/transform.moon | 8 ++++++-- 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/moonscript/compile/statement.lua b/moonscript/compile/statement.lua index afdcf888..81961543 100644 --- a/moonscript/compile/statement.lua +++ b/moonscript/compile/statement.lua @@ -242,7 +242,8 @@ local statement_compilers = { _with_0:stms(node[2]) return _with_0 end - end + end, + noop = function(self) end } return { statement_compilers = statement_compilers diff --git a/moonscript/compile/statement.moon b/moonscript/compile/statement.moon index e48e3978..cf89e144 100644 --- a/moonscript/compile/statement.moon +++ b/moonscript/compile/statement.moon @@ -135,5 +135,7 @@ statement_compilers = with @block! \stms node[2] + noop: => -- nothing! + { :statement_compilers } diff --git a/moonscript/transform.lua b/moonscript/transform.lua index c1bf9b72..edb2bcb0 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -67,7 +67,11 @@ apply_to_last = function(stms, fn) local _len_0 = 1 for i, stm in ipairs(stms) do if i == last_exp_id then - _accum_0[_len_0] = fn(stm) + _accum_0[_len_0] = { + "transform", + stm, + fn + } else _accum_0[_len_0] = stm end @@ -331,6 +335,11 @@ construct_comprehension = function(inner, clauses) return current_stms[1] end local Statement = Transformer({ + transform = function(self, tuple) + local _, node, fn + _, node, fn = tuple[1], tuple[2], tuple[3] + return fn(node) + end, root_stms = function(self, body) return apply_to_last(body, implicitly_return(self)) end, @@ -1354,7 +1363,9 @@ implicitly_return = function(scope) return scope.transform.statement(stm, fn) elseif types.manual_return[t] or not types.is_value(stm) then if is_top and t == "return" and stm[2] == "" then - return nil + return { + "noop" + } else return stm end diff --git a/moonscript/transform.moon b/moonscript/transform.moon index 5d3cbe93..1544adc4 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -32,7 +32,7 @@ apply_to_last = (stms, fn) -> return for i, stm in ipairs stms if i == last_exp_id - fn stm + {"transform", stm, fn} else stm @@ -150,6 +150,10 @@ construct_comprehension = (inner, clauses) -> current_stms[1] Statement = Transformer { + transform: (tuple) => + {_, node, fn} = tuple + fn node + root_stms: (body) => apply_to_last body, implicitly_return @ @@ -743,7 +747,7 @@ implicitly_return = (scope) -> elseif types.manual_return[t] or not types.is_value stm -- remove blank return statement if is_top and t == "return" and stm[2] == "" - nil + {"noop"} else stm else From 56112e074c1c71f5e32ea6b4125713cdeda52d4b Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Mon, 10 Jun 2013 16:12:26 -0700 Subject: [PATCH 111/554] with doesn't create its own reference unless necessary --- moonscript/transform.lua | 47 +++++++---- moonscript/transform.moon | 36 +++++--- spec/inputs/with.moon | 112 ++++++++++++++++--------- spec/outputs/export.lua | 1 - spec/outputs/with.lua | 172 ++++++++++++++++++++++++-------------- 5 files changed, 238 insertions(+), 130 deletions(-) diff --git a/moonscript/transform.lua b/moonscript/transform.lua index edb2bcb0..67d0b495 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -10,6 +10,9 @@ do NameProxy, LocalName = _table_0.NameProxy, _table_0.LocalName end local destructure = require("moonscript.transform.destructure") +local NOOP = { + "noop" +} local implicitly_return local Run do @@ -683,28 +686,38 @@ local Statement = Transformer({ return node end, with = function(self, node, ret) - local _, exp, block = unpack(node) - local scope_name = NameProxy("with") - local named_assign + local exp, block = unpack(node, 2) + local copy_scope = true + local scope_name, named_assign if ntype(exp) == "assign" then local names, values = unpack(exp, 2) - local assign_name = names[1] - exp = values[1] - values[1] = scope_name - named_assign = { - "assign", - names, - values - } + local first_name = names[1] + if ntype(first_name) == "value" then + scope_name = first_name + named_assign = exp + exp = values[1] + copy_scope = false + else + scope_name = NameProxy("with") + exp = values[1] + values[1] = scope_name + named_assign = { + "assign", + names, + values + } + end + elseif self:is_local(exp) then + scope_name = exp + copy_scope = false end + scope_name = scope_name or NameProxy("with") return build["do"]({ Run(function(self) return self:set("scope_var", scope_name) end), - build.assign_one(scope_name, exp), - build.group({ - named_assign - }), + copy_scope and build.assign_one(scope_name, exp) or NOOP, + named_assign or NOOP, build.group(block), (function() if ret then @@ -1363,9 +1376,7 @@ implicitly_return = function(scope) return scope.transform.statement(stm, fn) elseif types.manual_return[t] or not types.is_value(stm) then if is_top and t == "return" and stm[2] == "" then - return { - "noop" - } + return NOOP else return stm end diff --git a/moonscript/transform.moon b/moonscript/transform.moon index 1544adc4..49b896a8 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -9,6 +9,7 @@ import insert from table import NameProxy, LocalName from require "moonscript.transform.names" destructure = require "moonscript.transform.destructure" +NOOP = {"noop"} local implicitly_return @@ -339,21 +340,36 @@ Statement = Transformer { node with: (node, ret) => - _, exp, block = unpack node + exp, block = unpack node, 2 - scope_name = NameProxy "with" + copy_scope = true + local scope_name, named_assign - named_assign = if ntype(exp) == "assign" + if ntype(exp) == "assign" names, values = unpack exp, 2 - assign_name = names[1] - exp = values[1] - values[1] = scope_name - {"assign", names, values} + first_name = names[1] + + if ntype(first_name) == "value" + scope_name = first_name + named_assign = exp + exp = values[1] + copy_scope = false + else + scope_name = NameProxy "with" + exp = values[1] + values[1] = scope_name + named_assign = {"assign", names, values} + + elseif @is_local exp + scope_name = exp + copy_scope = false + + scope_name or= NameProxy "with" build.do { Run => @set "scope_var", scope_name - build.assign_one scope_name, exp - build.group { named_assign } + copy_scope and build.assign_one(scope_name, exp) or NOOP + named_assign or NOOP build.group block if ret @@ -747,7 +763,7 @@ implicitly_return = (scope) -> elseif types.manual_return[t] or not types.is_value stm -- remove blank return statement if is_top and t == "return" and stm[2] == "" - {"noop"} + NOOP else stm else diff --git a/spec/inputs/with.moon b/spec/inputs/with.moon index 2f0bcaf1..54aa5091 100644 --- a/spec/inputs/with.moon +++ b/spec/inputs/with.moon @@ -1,63 +1,97 @@ -a = -> - with something - print .hello - print hi - print "world" +do + a = -> + with something + print .hello + print hi + print "world" -with leaf - .world! - .world 1,2,3 +do + with leaf + .world! + .world 1,2,3 - g = .what.is.this + g = .what.is.this - .hi 1,2,3 + .hi 1,2,3 - \hi(1,2).world 2323 + \hi(1,2).world 2323 - \hi "yeah", "man" - .world = 200 + \hi "yeah", "man" + .world = 200 -zyzyzy = with something - .set_state "hello world" +do + zyzyzy = with something + .set_state "hello world" +do + x = 5 + with Something! + \write "hello world" -x = 5 + with Something! - \write "hello world" +do + x = { + hello: with yeah + \okay! + } -x = { - hello: with yeah - \okay! -} +do + with foo + \prop"something".hello + .prop\send(one) + .prop\send one -with foo - \prop"something".hello - .prop\send(one) - .prop\send one +-- + +do + with a, b -- b is lost + print .world + + mod = with _M = {} + .Thing = "hi" + + -- operate on a only + with a, b = something, pooh + print .world + + x = with a, b = 1, 2 + print a + b + + print with a, b = 1, 2 + print a + b + + -- assignment lhs must be evaluated in the order they appear + p = with hello!.x, world!.y = 1, 2 + print a + b -- -with a, b -- b is lost - print .world +do + x = "hello" + with x + x\upper! -mod = with _M = {} - .Thing = "hi" +do + with k = "jo" + print \upper! --- operate on a only -with a, b = something, pooh - print .world +do + with a,b,c = "", "", "" + print \upper! -x = with a, b = 1, 2 - print a + b +do + a = "bunk" + with a,b,c = "", "", "" + print \upper! -print with a, b = 1, 2 - print a + b +do + with j + print \upper! --- assignment lhs must be evaluated in the order they appear -p = with hello!.x, world!.y = 1, 2 - print a + b +do + with k.j = "jo" + print \upper! diff --git a/spec/outputs/export.lua b/spec/outputs/export.lua index 44ac1e8e..20b7531e 100644 --- a/spec/outputs/export.lua +++ b/spec/outputs/export.lua @@ -76,7 +76,6 @@ do local hallo = 3434 end do - local _with_0 = tmp local j = 2000 end end diff --git a/spec/outputs/with.lua b/spec/outputs/with.lua index 469e434e..d1d104a0 100644 --- a/spec/outputs/with.lua +++ b/spec/outputs/with.lua @@ -1,88 +1,136 @@ -local a -a = function() +do + local a + a = function() + do + local _with_0 = something + print(_with_0.hello) + print(hi) + print("world") + return _with_0 + end + end +end +do + do + local _with_0 = leaf + _with_0.world() + _with_0.world(1, 2, 3) + local g = _with_0.what.is.this + _with_0.hi(1, 2, 3) + _with_0:hi(1, 2).world(2323) + _with_0:hi("yeah", "man") + _with_0.world = 200 + end +end +do + local zyzyzy do local _with_0 = something - print(_with_0.hello) - print(hi) - print("world") - return _with_0 + _with_0.set_state("hello world") + zyzyzy = _with_0 end end do - local _with_0 = leaf - _with_0.world() - _with_0.world(1, 2, 3) - local g = _with_0.what.is.this - _with_0.hi(1, 2, 3) - _with_0:hi(1, 2).world(2323) - _with_0:hi("yeah", "man") - _with_0.world = 200 + local x = 5 + (function() + do + local _with_0 = Something() + _with_0:write("hello world") + return _with_0 + end + end)() end -local zyzyzy do - local _with_0 = something - _with_0.set_state("hello world") - zyzyzy = _with_0 + local x = { + hello = (function() + do + local _with_0 = yeah + _with_0:okay() + return _with_0 + end + end)() + } end -local x = 5 + (function() +do do - local _with_0 = Something() - _with_0:write("hello world") - return _with_0 + local _with_0 = foo + local _ = _with_0:prop("something").hello + _with_0.prop:send(one) + _with_0.prop:send(one) + end +end +do + do + local _with_0 = a, b + print(_with_0.world) + end + local mod + do + local _M = { } + _M.Thing = "hi" + mod = _M + end + do + local a, b = something, pooh + print(a.world) + end + local x + do + local a, b = 1, 2 + print(a + b) + x = a end -end)() -x = { - hello = (function() + print((function() do - local _with_0 = yeah - _with_0:okay() - return _with_0 + local a, b = 1, 2 + print(a + b) + return a end - end)() -} + end)()) + local p + do + local _with_0 = 1 + hello().x, world().y = _with_0, 2 + print(a + b) + p = _with_0 + end +end do - local _with_0 = foo - local _ = _with_0:prop("something").hello - _with_0.prop:send(one) - _with_0.prop:send(one) + local x = "hello" + do + x:upper() + end end do - local _with_0 = a, b - print(_with_0.world) + do + local k = "jo" + print(k:upper()) + end end -local mod do - local _with_0 = { } - local _M = _with_0 - _with_0.Thing = "hi" - mod = _with_0 + do + local a, b, c = "", "", "" + print(a:upper()) + end end do - local _with_0 = something - local b - a, b = _with_0, pooh - print(_with_0.world) + local a = "bunk" + do + local b, c + a, b, c = "", "", "" + print(a:upper()) + end end do - local _with_0 = 1 - local b - a, b = _with_0, 2 - print(a + b) - x = _with_0 + do + local _with_0 = j + print(_with_0:upper()) + end end -print((function() +do do - local _with_0 = 1 - local b - a, b = _with_0, 2 - print(a + b) + local _with_0 = "jo" + k.j = _with_0 + print(_with_0:upper()) return _with_0 end -end)()) -local p -do - local _with_0 = 1 - hello().x, world().y = _with_0, 2 - print(a + b) - p = _with_0 end \ No newline at end of file From 1311671cdcdbaaa0e33f32192b37ffeed234137d Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Mon, 10 Jun 2013 16:20:44 -0700 Subject: [PATCH 112/554] rebuild --- moonscript/compile.lua | 8 ++---- moonscript/transform.lua | 42 +++++++++++++--------------- moonscript/transform/destructure.lua | 10 +++---- 3 files changed, 27 insertions(+), 33 deletions(-) diff --git a/moonscript/compile.lua b/moonscript/compile.lua index e674f746..11689637 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -624,10 +624,9 @@ do self._state = { } self._listeners = { } do - local _with_0 = transform self.transform = { - value = _with_0.Value:bind(self), - statement = _with_0.Statement:bind(self) + value = transform.Value:bind(self), + statement = transform.Statement:bind(self) } end if self.parent then @@ -776,8 +775,7 @@ tree = function(tree, options) end end do - local _with_0 = require("moonscript.data") - local data = _with_0 + local data = require("moonscript.data") for name, cls in pairs({ Line = Line, Lines = Lines, diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 67d0b495..828ab93b 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -736,10 +736,9 @@ local Statement = Transformer({ for i, name in ipairs(node.names) do if ntype(name) == "table" then do - local _with_0 = NameProxy("des") - local proxy = _with_0 + local proxy = NameProxy("des") insert(destructures, destructure.build_assign(self, name, proxy)) - _accum_0[_len_0] = _with_0 + _accum_0[_len_0] = proxy end else _accum_0[_len_0] = name @@ -1103,7 +1102,6 @@ local Statement = Transformer({ }) local value = nil do - local _with_0 = build local out_body = { Run(function(self) if name then @@ -1180,22 +1178,22 @@ local Statement = Transformer({ "declare_glob", "*" }, - _with_0.assign_one(parent_cls_name, parent_val == "" and "nil" or parent_val), - _with_0.assign_one(base_name, { + build.assign_one(parent_cls_name, parent_val == "" and "nil" or parent_val), + build.assign_one(base_name, { "table", properties }), - _with_0.assign_one(base_name:chain("__index"), base_name), - _with_0["if"]({ + build.assign_one(base_name:chain("__index"), base_name), + build["if"]({ cond = parent_cls_name, ["then"] = { - _with_0.chain({ + build.chain({ base = "setmetatable", { "call", { base_name, - _with_0.chain({ + build.chain({ base = parent_cls_name, { "dot", @@ -1207,17 +1205,17 @@ local Statement = Transformer({ }) } }), - _with_0.assign_one(cls_name, cls), - _with_0.assign_one(base_name:chain("__class"), cls_name), - _with_0.group((function() + build.assign_one(cls_name, cls), + build.assign_one(base_name:chain("__class"), cls_name), + build.group((function() if #statements > 0 then return { - _with_0.assign_one(LocalName("self"), cls_name), - _with_0.group(statements) + build.assign_one(LocalName("self"), cls_name), + build.group(statements) } end end)()), - _with_0["if"]({ + build["if"]({ cond = { "exp", parent_cls_name, @@ -1234,10 +1232,10 @@ local Statement = Transformer({ }) } }), - _with_0.group((function() + build.group((function() if name then return { - _with_0.assign_one(name, cls_name) + build.assign_one(name, cls_name) } end end)()), @@ -1247,11 +1245,11 @@ local Statement = Transformer({ end end)() } - value = _with_0.group({ - _with_0.group((function() + value = build.group({ + build.group((function() if ntype(name) == "value" then return { - _with_0.declare({ + build.declare({ names = { name } @@ -1259,7 +1257,7 @@ local Statement = Transformer({ } end end)()), - _with_0["do"](out_body) + build["do"](out_body) }) end return value diff --git a/moonscript/transform/destructure.lua b/moonscript/transform/destructure.lua index 0e534215..a8d6dab0 100644 --- a/moonscript/transform/destructure.lua +++ b/moonscript/transform/destructure.lua @@ -22,8 +22,7 @@ end local join join = function(...) do - local _with_0 = { } - local out = _with_0 + local out = { } local i = 1 local _list_0 = { ... @@ -37,7 +36,7 @@ join = function(...) i = i + 1 end end - return _with_0 + return out end end local has_destructure @@ -122,8 +121,7 @@ build_assign = function(scope, destruct_literal, receiver) obj = receiver else do - local _with_0 = NameProxy("obj") - obj = _with_0 + obj = NameProxy("obj") inner = build["do"]({ build.assign_one(obj, receiver), { @@ -132,7 +130,7 @@ build_assign = function(scope, destruct_literal, receiver) values } }) - obj = _with_0 + obj = obj end end local _list_0 = extracted_names From 4978054a8fada26b7a1870d456a4a243c6efd721 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Mon, 10 Jun 2013 19:18:49 -0700 Subject: [PATCH 113/554] reuse locals for unpack loops --- moonscript/transform.lua | 8 ++-- moonscript/transform.moon | 8 ++-- spec/inputs/loops.moon | 8 ++++ spec/outputs/destructure.lua | 5 +-- spec/outputs/lists.lua | 87 ++++++++++++++++-------------------- spec/outputs/loops.lua | 22 ++++++--- 6 files changed, 73 insertions(+), 65 deletions(-) diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 828ab93b..0b0e7f01 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -754,7 +754,7 @@ local Statement = Transformer({ if ntype(source) == "unpack" then local list = source[2] local index_name = NameProxy("index") - local list_name = NameProxy("list") + local list_name = self:is_local(list) and list or NameProxy("list") local slice_var = nil local bounds if is_slice(list) then @@ -796,8 +796,8 @@ local Statement = Transformer({ } end return build.group({ - build.assign_one(list_name, list), - slice_var, + list_name ~= list and build.assign_one(list_name, list) or NOOP, + slice_var or NOOP, build["for"]({ name = index_name, bounds = bounds, @@ -806,7 +806,7 @@ local Statement = Transformer({ "assign", node.names, { - list_name:index(index_name) + NameProxy.index(list_name, index_name) } }, build.group(node.body) diff --git a/moonscript/transform.moon b/moonscript/transform.moon index 49b896a8..973c66a4 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -396,7 +396,7 @@ Statement = Transformer { list = source[2] index_name = NameProxy "index" - list_name = NameProxy "list" + list_name = @is_local(list) and list or NameProxy "list" slice_var = nil bounds = if is_slice list @@ -418,13 +418,13 @@ Statement = Transformer { {1, {"length", list_name}} return build.group { - build.assign_one list_name, list - slice_var + list_name != list and build.assign_one(list_name, list) or NOOP + slice_var or NOOP build["for"] { name: index_name bounds: bounds body: { - {"assign", node.names, {list_name\index index_name}} + {"assign", node.names, { NameProxy.index list_name, index_name }} build.group node.body } } diff --git a/spec/inputs/loops.moon b/spec/inputs/loops.moon index 6d37a82e..fbdc6380 100644 --- a/spec/inputs/loops.moon +++ b/spec/inputs/loops.moon @@ -114,3 +114,11 @@ for x=1,10 for y = 2,12 continue if y % 3 == 0 +-- + +do + xxx = {1,2,3,4} + for thing in *xxx + print thing + + diff --git a/spec/outputs/destructure.lua b/spec/outputs/destructure.lua index 0ffc9ccb..28315438 100644 --- a/spec/outputs/destructure.lua +++ b/spec/outputs/destructure.lua @@ -101,9 +101,8 @@ do 4 } } - local _list_0 = thing - for _index_0 = 1, #_list_0 do - local _des_0 = _list_0[_index_0] + for _index_0 = 1, #thing do + local _des_0 = thing[_index_0] local x, y x, y = _des_0[1], _des_0[2] print(x, y) diff --git a/spec/outputs/lists.lua b/spec/outputs/lists.lua index b6f1b299..e5ce5141 100644 --- a/spec/outputs/lists.lua +++ b/spec/outputs/lists.lua @@ -164,25 +164,22 @@ end local double = (function() local _accum_0 = { } local _len_0 = 1 - local _list_0 = items - for _index_0 = 1, #_list_0 do - x = _list_0[_index_0] + for _index_0 = 1, #items do + x = items[_index_0] _accum_0[_len_0] = x * 2 _len_0 = _len_0 + 1 end return _accum_0 end)() -local _list_0 = double -for _index_0 = 1, #_list_0 do - x = _list_0[_index_0] +for _index_0 = 1, #double do + x = double[_index_0] print(x) end local cut = (function() local _accum_0 = { } local _len_0 = 1 - local _list_1 = items - for _index_0 = 1, #_list_1 do - x = _list_1[_index_0] + for _index_0 = 1, #items do + x = items[_index_0] if x > 3 then _accum_0[_len_0] = x _len_0 = _len_0 + 1 @@ -193,21 +190,18 @@ end)() local hello = (function() local _accum_0 = { } local _len_0 = 1 - local _list_1 = items - for _index_0 = 1, #_list_1 do - x = _list_1[_index_0] - local _list_2 = items - for _index_1 = 1, #_list_2 do - local y = _list_2[_index_1] + for _index_0 = 1, #items do + x = items[_index_0] + for _index_1 = 1, #items do + local y = items[_index_1] _accum_0[_len_0] = x + y _len_0 = _len_0 + 1 end end return _accum_0 end)() -local _list_1 = hello -for _index_0 = 1, #_list_1 do - local z = _list_1[_index_0] +for _index_0 = 1, #hello do + local z = hello[_index_0] print(z) end x = { @@ -219,38 +213,38 @@ x = { 6, 7 } -local _list_2 = x +local _list_0 = x local _max_0 = -5 -for _index_0 = 2, _max_0 < 0 and #_list_2 + _max_0 or _max_0, 2 do - local y = _list_2[_index_0] +for _index_0 = 2, _max_0 < 0 and #_list_0 + _max_0 or _max_0, 2 do + local y = _list_0[_index_0] print(y) end -local _list_3 = x +local _list_1 = x local _max_1 = 3 -for _index_0 = 1, _max_1 < 0 and #_list_3 + _max_1 or _max_1 do - local y = _list_3[_index_0] +for _index_0 = 1, _max_1 < 0 and #_list_1 + _max_1 or _max_1 do + local y = _list_1[_index_0] print(y) end -local _list_4 = x -for _index_0 = 2, #_list_4 do - local y = _list_4[_index_0] +local _list_2 = x +for _index_0 = 2, #_list_2 do + local y = _list_2[_index_0] print(y) end -local _list_5 = x -for _index_0 = 1, #_list_5, 2 do - local y = _list_5[_index_0] +local _list_3 = x +for _index_0 = 1, #_list_3, 2 do + local y = _list_3[_index_0] print(y) end -local _list_6 = x -for _index_0 = 2, #_list_6, 2 do - local y = _list_6[_index_0] +local _list_4 = x +for _index_0 = 2, #_list_4, 2 do + local y = _list_4[_index_0] print(y) end local a, b, c = 1, 5, 2 -local _list_7 = x +local _list_5 = x local _max_2 = b -for _index_0 = a, _max_2 < 0 and #_list_7 + _max_2 or _max_2, c do - local y = _list_7[_index_0] +for _index_0 = a, _max_2 < 0 and #_list_5 + _max_2 or _max_2, c do + local y = _list_5[_index_0] print(y) end local normal @@ -266,23 +260,21 @@ normal = function(hello) end)() end local test = x(1, 2, 3, 4, 5) -local _list_8 = test -for _index_0 = 1, #_list_8 do - local thing = _list_8[_index_0] +for _index_0 = 1, #test do + local thing = test[_index_0] print(thing) end local _ _ = function() - local _list_9 = rows - for _index_0 = 1, #_list_9 do - local row = _list_9[_index_0] + local _list_6 = rows + for _index_0 = 1, #_list_6 do + local row = _list_6[_index_0] a = b end end _ = function() - local _list_9 = things - for _index_0 = 1, #_list_9 do - x = _list_9[_index_0] + for _index_0 = 1, #things do + x = things[_index_0] _ = x end end @@ -290,9 +282,8 @@ return function() return (function() local _accum_0 = { } local _len_0 = 1 - local _list_9 = things - for _index_0 = 1, #_list_9 do - x = _list_9[_index_0] + for _index_0 = 1, #things do + x = things[_index_0] _accum_0[_len_0] = x _len_0 = _len_0 + 1 end diff --git a/spec/outputs/loops.lua b/spec/outputs/loops.lua index 87824e81..47df0d7c 100644 --- a/spec/outputs/loops.lua +++ b/spec/outputs/loops.lua @@ -51,9 +51,8 @@ local hello = { x = (function() local _accum_0 = { } local _len_0 = 1 - local _list_1 = hello - for _index_0 = 1, #_list_1 do - local y = _list_1[_index_0] + for _index_0 = 1, #hello do + local y = hello[_index_0] if y % 2 == 0 then _accum_0[_len_0] = y end @@ -62,9 +61,8 @@ x = (function() return _accum_0 end)() x = function() - local _list_1 = hello - for _index_0 = 1, #_list_1 do - x = _list_1[_index_0] + for _index_0 = 1, #hello do + x = hello[_index_0] local _ = y end end @@ -258,4 +256,16 @@ for x = 1, 10 do if not _continue_0 then break end +end +do + local xxx = { + 1, + 2, + 3, + 4 + } + for _index_0 = 1, #xxx do + local thing = xxx[_index_0] + print(thing) + end end \ No newline at end of file From dc9d5507a11e4857288bffb260a072faae9d84e8 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Mon, 10 Jun 2013 19:20:44 -0700 Subject: [PATCH 114/554] rebuild --- moon/init.lua | 10 ++--- moonscript/compile.lua | 31 +++++++-------- moonscript/compile/statement.lua | 30 ++++++--------- moonscript/compile/value.lua | 25 +++++------- moonscript/data.lua | 5 +-- moonscript/dump.lua | 5 +-- moonscript/transform.lua | 57 ++++++++++++---------------- moonscript/transform/destructure.lua | 15 +++----- moonscript/types.lua | 10 ++--- moonscript/util.lua | 5 +-- 10 files changed, 79 insertions(+), 114 deletions(-) diff --git a/moon/init.lua b/moon/init.lua index 91d20e24..5d80e525 100644 --- a/moon/init.lua +++ b/moon/init.lua @@ -125,9 +125,8 @@ mixin = function(self, cls, ...) return cls.__init(self, ...) end mixin_object = function(self, object, methods) - local _list_0 = methods - for _index_0 = 1, #_list_0 do - local name = _list_0[_index_0] + for _index_0 = 1, #methods do + local name = methods[_index_0] self[name] = function(parent, ...) return object[name](object, ...) end @@ -135,9 +134,8 @@ mixin_object = function(self, object, methods) end mixin_table = function(self, tbl, keys) if keys then - local _list_0 = keys - for _index_0 = 1, #_list_0 do - local key = _list_0[_index_0] + for _index_0 = 1, #keys do + local key = keys[_index_0] self[key] = tbl[key] end else diff --git a/moonscript/compile.lua b/moonscript/compile.lua index 11689637..be64604c 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -118,9 +118,8 @@ do return (function() local _accum_0 = { } local _len_0 = 1 - local _list_0 = t - for _index_0 = 1, #_list_0 do - local v = _list_0[_index_0] + for _index_0 = 1, #t do + local v = t[_index_0] _accum_0[_len_0] = strip(v) _len_0 = _len_0 + 1 end @@ -174,9 +173,8 @@ do if not (self.pos) then self.pos = item.pos end - local _list_0 = item - for _index_0 = 1, #_list_0 do - local value = _list_0[_index_0] + for _index_0 = 1, #item do + local value = item[_index_0] self:_append_single(value) end else @@ -210,14 +208,13 @@ do buffer:add(concat(current)) return buffer:mark_pos(self.pos) end - local _list_0 = self - for _index_0 = 1, #_list_0 do - local chunk = _list_0[_index_0] + for _index_0 = 1, #self do + local chunk = self[_index_0] local _exp_0 = mtype(chunk) if Block == _exp_0 then - local _list_1 = chunk:render(Lines()) - for _index_1 = 1, #_list_1 do - local block_chunk = _list_1[_index_1] + local _list_0 = chunk:render(Lines()) + for _index_1 = 1, #_list_0 do + local block_chunk = _list_0[_index_1] if "string" == type(block_chunk) then insert(current, block_chunk) else @@ -357,11 +354,10 @@ do local undeclared = (function() local _accum_0 = { } local _len_0 = 1 - local _list_0 = names - for _index_0 = 1, #_list_0 do + for _index_0 = 1, #names do local _continue_0 = false repeat - local name = _list_0[_index_0] + local name = names[_index_0] local is_local = false local real_name local _exp_0 = mtype(name) @@ -543,9 +539,8 @@ do _with_0:append_list((function() local _accum_0 = { } local _len_0 = 1 - local _list_0 = values - for _index_0 = 1, #_list_0 do - local v = _list_0[_index_0] + for _index_0 = 1, #values do + local v = values[_index_0] _accum_0[_len_0] = self:value(v) _len_0 = _len_0 + 1 end diff --git a/moonscript/compile/statement.lua b/moonscript/compile/statement.lua index 81961543..b7519487 100644 --- a/moonscript/compile/statement.lua +++ b/moonscript/compile/statement.lua @@ -27,9 +27,8 @@ local statement_compilers = { _with_0:append_list((function() local _accum_0 = { } local _len_0 = 1 - local _list_0 = undeclared - for _index_0 = 1, #_list_0 do - local name = _list_0[_index_0] + for _index_0 = 1, #undeclared do + local name = undeclared[_index_0] _accum_0[_len_0] = self:name(name) _len_0 = _len_0 + 1 end @@ -47,9 +46,8 @@ local statement_compilers = { _with_0:append_list((function() local _accum_0 = { } local _len_0 = 1 - local _list_0 = names - for _index_0 = 1, #_list_0 do - local name = _list_0[_index_0] + for _index_0 = 1, #names do + local name = names[_index_0] _accum_0[_len_0] = self:name(name) _len_0 = _len_0 + 1 end @@ -81,9 +79,8 @@ local statement_compilers = { _with_0:append_list((function() local _accum_0 = { } local _len_0 = 1 - local _list_0 = names - for _index_0 = 1, #_list_0 do - local name = _list_0[_index_0] + for _index_0 = 1, #names do + local name = names[_index_0] _accum_0[_len_0] = self:value(name) _len_0 = _len_0 + 1 end @@ -94,9 +91,8 @@ local statement_compilers = { _with_0:append_list((function() local _accum_0 = { } local _len_0 = 1 - local _list_0 = values - for _index_0 = 1, #_list_0 do - local v = _list_0[_index_0] + for _index_0 = 1, #values do + local v = values[_index_0] _accum_0[_len_0] = self:value(v) _len_0 = _len_0 + 1 end @@ -190,9 +186,8 @@ local statement_compilers = { loop:append_list((function() local _accum_0 = { } local _len_0 = 1 - local _list_0 = names - for _index_0 = 1, #_list_0 do - local name = _list_0[_index_0] + for _index_0 = 1, #names do + local name = names[_index_0] _accum_0[_len_0] = _with_0:name(name, false) _len_0 = _len_0 + 1 end @@ -202,9 +197,8 @@ local statement_compilers = { loop:append_list((function() local _accum_0 = { } local _len_0 = 1 - local _list_0 = exps - for _index_0 = 1, #_list_0 do - local exp = _list_0[_index_0] + for _index_0 = 1, #exps do + local exp = exps[_index_0] _accum_0[_len_0] = self:value(exp) _len_0 = _len_0 + 1 end diff --git a/moonscript/compile/value.lua b/moonscript/compile/value.lua index 28b2cb3b..b0cab82e 100644 --- a/moonscript/compile/value.lua +++ b/moonscript/compile/value.lua @@ -126,9 +126,8 @@ local value_compilers = { local arg_names = (function() local _accum_0 = { } local _len_0 = 1 - local _list_0 = args - for _index_0 = 1, #_list_0 do - local arg = _list_0[_index_0] + for _index_0 = 1, #args do + local arg = args[_index_0] local name, default_value = unpack(arg) if type(name) == "string" then name = name @@ -155,14 +154,12 @@ local value_compilers = { if #whitelist > 0 then _with_0:whitelist_names(whitelist) end - local _list_0 = arg_names - for _index_0 = 1, #_list_0 do - local name = _list_0[_index_0] + for _index_0 = 1, #arg_names do + local name = arg_names[_index_0] _with_0:put_name(name) end - local _list_1 = default_args - for _index_0 = 1, #_list_1 do - local default = _list_1[_index_0] + for _index_0 = 1, #default_args do + local default = default_args[_index_0] local name, value = unpack(default) if type(name) == "table" then name = name[2] @@ -191,9 +188,8 @@ local value_compilers = { local self_arg_values = (function() local _accum_0 = { } local _len_0 = 1 - local _list_2 = self_args - for _index_0 = 1, #_list_2 do - local arg = _list_2[_index_0] + for _index_0 = 1, #self_args do + local arg = self_args[_index_0] _accum_0[_len_0] = arg[2] _len_0 = _len_0 + 1 end @@ -211,9 +207,8 @@ local value_compilers = { arg_names = (function() local _accum_0 = { } local _len_0 = 1 - local _list_2 = args - for _index_0 = 1, #_list_2 do - local arg = _list_2[_index_0] + for _index_0 = 1, #args do + local arg = args[_index_0] _accum_0[_len_0] = arg[1] _len_0 = _len_0 + 1 end diff --git a/moonscript/data.lua b/moonscript/data.lua index b968d91f..a2e99fb3 100644 --- a/moonscript/data.lua +++ b/moonscript/data.lua @@ -2,9 +2,8 @@ local concat, remove, insert = table.concat, table.remove, table.insert local Set Set = function(items) local self = { } - local _list_0 = items - for _index_0 = 1, #_list_0 do - local key = _list_0[_index_0] + for _index_0 = 1, #items do + local key = items[_index_0] self[key] = true end return self diff --git a/moonscript/dump.lua b/moonscript/dump.lua index edfe4004..5b5fea2a 100644 --- a/moonscript/dump.lua +++ b/moonscript/dump.lua @@ -12,9 +12,8 @@ flat_value = function(op, depth) local items = (function() local _accum_0 = { } local _len_0 = 1 - local _list_0 = op - for _index_0 = 1, #_list_0 do - local item = _list_0[_index_0] + for _index_0 = 1, #op do + local item = op[_index_0] _accum_0[_len_0] = flat_value(item, depth + 1) _len_0 = _len_0 + 1 end diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 0b0e7f01..ae57a2d4 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -352,11 +352,10 @@ local Statement = Transformer({ names = (function() local _accum_0 = { } local _len_0 = 1 - local _list_0 = names - for _index_0 = 1, #_list_0 do + for _index_0 = 1, #names do local _continue_0 = false repeat - local name = _list_0[_index_0] + local name = names[_index_0] if not (name:match("^%u")) then _continue_0 = true break @@ -480,9 +479,8 @@ local Statement = Transformer({ local stubs = (function() local _accum_0 = { } local _len_0 = 1 - local _list_0 = names - for _index_0 = 1, #_list_0 do - local name = _list_0[_index_0] + for _index_0 = 1, #names do + local name = names[_index_0] if type(name) == "table" then _accum_0[_len_0] = name else @@ -498,9 +496,8 @@ local Statement = Transformer({ local real_names = (function() local _accum_0 = { } local _len_0 = 1 - local _list_0 = names - for _index_0 = 1, #_list_0 do - local name = _list_0[_index_0] + for _index_0 = 1, #names do + local name = names[_index_0] _accum_0[_len_0] = type(name) == "table" and name[2] or name _len_0 = _len_0 + 1 end @@ -512,9 +509,8 @@ local Statement = Transformer({ values = (function() local _accum_0 = { } local _len_0 = 1 - local _list_0 = stubs - for _index_0 = 1, #_list_0 do - local stub = _list_0[_index_0] + for _index_0 = 1, #stubs do + local stub = stubs[_index_0] _accum_0[_len_0] = build.chain({ base = source, stub @@ -538,9 +534,8 @@ local Statement = Transformer({ values = (function() local _accum_0 = { } local _len_0 = 1 - local _list_0 = stubs - for _index_0 = 1, #_list_0 do - local stub = _list_0[_index_0] + for _index_0 = 1, #stubs do + local stub = stubs[_index_0] _accum_0[_len_0] = build.chain({ base = source_name, stub @@ -867,9 +862,8 @@ local Statement = Transformer({ local if_stm = { "if" } - local _list_0 = conds - for _index_0 = 1, #_list_0 do - local cond = _list_0[_index_0] + for _index_0 = 1, #conds do + local cond = conds[_index_0] local if_cond = convert_cond(cond) if first then first = false @@ -888,16 +882,15 @@ local Statement = Transformer({ local _, name, parent_val, body = unpack(node) local statements = { } local properties = { } - local _list_0 = body - for _index_0 = 1, #_list_0 do - local item = _list_0[_index_0] + for _index_0 = 1, #body do + local item = body[_index_0] local _exp_0 = item[1] if "stm" == _exp_0 then insert(statements, item[2]) elseif "props" == _exp_0 then - local _list_1 = item - for _index_1 = 2, #_list_1 do - local tuple = _list_1[_index_1] + local _list_0 = item + for _index_1 = 2, #_list_0 do + local tuple = _list_0[_index_1] if ntype(tuple[1]) == "self" then insert(statements, build.assign_one(unpack(tuple))) else @@ -910,11 +903,10 @@ local Statement = Transformer({ properties = (function() local _accum_0 = { } local _len_0 = 1 - local _list_1 = properties - for _index_0 = 1, #_list_1 do + for _index_0 = 1, #properties do local _continue_0 = false repeat - local tuple = _list_1[_index_0] + local tuple = properties[_index_0] local key = tuple[1] local _value_0 if key[1] == "key_literal" and key[2] == constructor_name then @@ -1112,9 +1104,9 @@ local Statement = Transformer({ local slice = (function() local _accum_0 = { } local _len_0 = 1 - local _list_1 = chain - for _index_0 = 3, #_list_1 do - local item = _list_1[_index_0] + local _list_0 = chain + for _index_0 = 3, #_list_0 do + local item = _list_0[_index_0] _accum_0[_len_0] = item _len_0 = _len_0 + 1 end @@ -1163,9 +1155,8 @@ local Statement = Transformer({ } } end - local _list_1 = slice - for _index_0 = 1, #_list_1 do - local item = _list_1[_index_0] + for _index_0 = 1, #slice do + local item = slice[_index_0] insert(new_chain, item) end return new_chain diff --git a/moonscript/transform/destructure.lua b/moonscript/transform/destructure.lua index a8d6dab0..7ad4b4ed 100644 --- a/moonscript/transform/destructure.lua +++ b/moonscript/transform/destructure.lua @@ -29,9 +29,8 @@ join = function(...) } for _index_0 = 1, #_list_0 do local tbl = _list_0[_index_0] - local _list_1 = tbl - for _index_1 = 1, #_list_1 do - local v = _list_1[_index_1] + for _index_1 = 1, #tbl do + local v = tbl[_index_1] out[i] = v i = i + 1 end @@ -41,9 +40,8 @@ join = function(...) end local has_destructure has_destructure = function(names) - local _list_0 = names - for _index_0 = 1, #_list_0 do - local n = _list_0[_index_0] + for _index_0 = 1, #names do + local n = names[_index_0] if ntype(n) == "table" then return true end @@ -133,9 +131,8 @@ build_assign = function(scope, destruct_literal, receiver) obj = obj end end - local _list_0 = extracted_names - for _index_0 = 1, #_list_0 do - local tuple = _list_0[_index_0] + for _index_0 = 1, #extracted_names do + local tuple = extracted_names[_index_0] insert(names, tuple[1]) insert(values, NameProxy.chain(obj, unpack(tuple[2]))) end diff --git a/moonscript/types.lua b/moonscript/types.lua index 3b1ad954..4a171a25 100644 --- a/moonscript/types.lua +++ b/moonscript/types.lua @@ -232,9 +232,8 @@ build = setmetatable({ if tbl == nil then tbl = { } end - local _list_0 = tbl - for _index_0 = 1, #_list_0 do - local tuple = _list_0[_index_0] + for _index_0 = 1, #tbl do + local tuple = tbl[_index_0] if type(tuple[1]) == "string" then tuple[1] = { "key_literal", @@ -259,9 +258,8 @@ build = setmetatable({ "chain", base } - local _list_0 = parts - for _index_0 = 1, #_list_0 do - local part = _list_0[_index_0] + for _index_0 = 1, #parts do + local part = parts[_index_0] insert(node, part) end return node diff --git a/moonscript/util.lua b/moonscript/util.lua index 54494659..090a9d08 100644 --- a/moonscript/util.lua +++ b/moonscript/util.lua @@ -137,9 +137,8 @@ debug_posmap = function(posmap, moon_code, lua_code) local lines = (function() local _accum_0 = { } local _len_0 = 1 - local _list_0 = tuples - for _index_0 = 1, #_list_0 do - local pair = _list_0[_index_0] + for _index_0 = 1, #tuples do + local pair = tuples[_index_0] local lua_line, pos = unpack(pair) local moon_line = pos_to_line(moon_code, pos) local lua_text = get_line(lua_code, lua_line) From f8c2e0b3abe0583e7b569c8c3c2cd432e192ef2d Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Mon, 10 Jun 2013 19:57:01 -0700 Subject: [PATCH 115/554] avoid creating function for basic list comprehension assign --- moonscript/transform.lua | 51 +++++---- moonscript/transform.moon | 33 ++++-- spec/outputs/bubbling.lua | 89 +++++++-------- spec/outputs/comprehension.lua | 108 ++++++++----------- spec/outputs/lists.lua | 192 +++++++++++++++------------------ 5 files changed, 222 insertions(+), 251 deletions(-) diff --git a/moonscript/transform.lua b/moonscript/transform.lua index ae57a2d4..00d89fee 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -13,8 +13,7 @@ local destructure = require("moonscript.transform.destructure") local NOOP = { "noop" } -local implicitly_return -local Run +local Run, apply_to_last, is_singular, extract_declarations, expand_elseif_assign, constructor_name, with_continue_listener, Transformer, construct_comprehension, Statement, Accumulator, default_accumulator, implicitly_return, Value do local _parent_0 = nil local _base_0 = { @@ -55,7 +54,6 @@ do end Run = _class_0 end -local apply_to_last apply_to_last = function(stms, fn) local last_exp_id = 0 for i = #stms, 1, -1 do @@ -83,7 +81,6 @@ apply_to_last = function(stms, fn) return _accum_0 end)() end -local is_singular is_singular = function(body) if #body ~= 1 then return false @@ -94,7 +91,6 @@ is_singular = function(body) return body[1] end end -local extract_declarations extract_declarations = function(self, body, start, out) if body == nil then body = self.current_stms @@ -135,7 +131,6 @@ extract_declarations = function(self, body, start, out) end return out end -local expand_elseif_assign expand_elseif_assign = function(ifstm) for i = 4, #ifstm do local case = ifstm[i] @@ -159,8 +154,7 @@ expand_elseif_assign = function(ifstm) end return ifstm end -local constructor_name = "new" -local with_continue_listener +constructor_name = "new" with_continue_listener = function(body) local continue_name = nil return { @@ -223,7 +217,6 @@ with_continue_listener = function(body) end) } end -local Transformer do local _parent_0 = nil local _base_0 = { @@ -294,7 +287,6 @@ do end Transformer = _class_0 end -local construct_comprehension construct_comprehension = function(inner, clauses) local current_stms = inner for _, clause in reversed(clauses) do @@ -337,7 +329,7 @@ construct_comprehension = function(inner, clauses) end return current_stms[1] end -local Statement = Transformer({ +Statement = Transformer({ transform = function(self, tuple) local _, node, fn _, node, fn = tuple[1], tuple[2], tuple[3] @@ -379,8 +371,24 @@ local Statement = Transformer({ end, assign = function(self, node) local names, values = unpack(node, 2) + local num_values = #values + local num_names = #values + if num_names == 1 and num_values == 1 then + local first_value = values[1] + local _exp_0 = ntype(first_value) + if "comprehension" == _exp_0 then + local first_name = names[1] + local a = Accumulator(first_name) + node = self.transform.statement(first_value, function(exp) + return a:mutate_body({ + exp + }) + end) + return a:wrap(node, "group") + end + end local transformed - if #values == 1 then + if num_values == 1 then local value = values[1] local t = ntype(value) if t == "decorated" then @@ -1254,7 +1262,6 @@ local Statement = Transformer({ return value end }) -local Accumulator do local _parent_0 = nil local _base_0 = { @@ -1268,12 +1275,15 @@ do node[index] = self:mutate_body(node[index]) return self:wrap(node) end, - wrap = function(self, node) - return build.block_exp({ + wrap = function(self, node, group_type) + if group_type == nil then + group_type = "block_exp" + end + return build[group_type]({ build.assign_one(self.accum_name, build.table()), build.assign_one(self.len_name, 1), node, - self.accum_name + group_type == "block_exp" and self.accum_name or NOOP }) end, mutate_body = function(self, body) @@ -1301,7 +1311,7 @@ do val = self.value_name end local update = { - build.assign_one(self.accum_name:index(self.len_name), val), + build.assign_one(NameProxy.index(self.accum_name, self.len_name), val), { "update", self.len_name, @@ -1318,8 +1328,8 @@ do setmetatable(_base_0, _parent_0.__base) end local _class_0 = setmetatable({ - __init = function(self) - self.accum_name = NameProxy("accum") + __init = function(self, accum_name) + self.accum_name = accum_name or NameProxy("accum") self.value_name = NameProxy("value") self.len_name = NameProxy("len") end, @@ -1347,7 +1357,6 @@ do end Accumulator = _class_0 end -local default_accumulator default_accumulator = function(self, node) return Accumulator():convert(node) end @@ -1382,7 +1391,7 @@ implicitly_return = function(scope) end return fn end -local Value = Transformer({ +Value = Transformer({ ["for"] = default_accumulator, ["while"] = default_accumulator, foreach = default_accumulator, diff --git a/moonscript/transform.moon b/moonscript/transform.moon index 973c66a4..07706b0b 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -11,7 +11,7 @@ import NameProxy, LocalName from require "moonscript.transform.names" destructure = require "moonscript.transform.destructure" NOOP = {"noop"} -local implicitly_return +local * class Run new: (@fn) => @@ -171,8 +171,23 @@ Statement = Transformer { assign: (node) => names, values = unpack node, 2 + num_values = #values + num_names = #values + + if num_names == 1 and num_values == 1 + first_value = values[1] + switch ntype first_value + when "comprehension" + first_name = names[1] + + a = Accumulator first_name + node = @transform.statement first_value, (exp) -> + a\mutate_body { exp } + + return a\wrap node, "group" + -- bubble cascading assigns - transformed = if #values == 1 + transformed = if num_values == 1 value = values[1] t = ntype value @@ -194,11 +209,9 @@ Statement = Transformer { node = transformed or node - if destructure.has_destructure names return destructure.split_assign @, node - -- print util.dump node node continue: (node) => @@ -697,8 +710,8 @@ Statement = Transformer { class Accumulator body_idx: { for: 4, while: 3, foreach: 4 } - new: => - @accum_name = NameProxy "accum" + new: (accum_name) => + @accum_name = accum_name or NameProxy "accum" @value_name = NameProxy "value" @len_name = NameProxy "len" @@ -709,12 +722,12 @@ class Accumulator @wrap node -- wrap the node into a block_exp - wrap: (node) => - build.block_exp { + wrap: (node, group_type="block_exp") => + build[group_type] { build.assign_one @accum_name, build.table! build.assign_one @len_name, 1 node - @accum_name + group_type == "block_exp" and @accum_name or NOOP } -- mutates the body of a loop construct to save last value into accumulator @@ -737,7 +750,7 @@ class Accumulator @value_name update = { - build.assign_one @accum_name\index(@len_name), val + build.assign_one NameProxy.index(@accum_name, @len_name), val {"update", @len_name, "+=", 1} } diff --git a/spec/outputs/bubbling.lua b/spec/outputs/bubbling.lua index 651b0e2b..4d83336f 100644 --- a/spec/outputs/bubbling.lua +++ b/spec/outputs/bubbling.lua @@ -18,25 +18,22 @@ dont_bubble = function() return _accum_0 end)() end -local k = (function() - local _accum_0 = { } - local _len_0 = 1 - for x in (function(...) - return print(...) - end)("hello") do - _accum_0[_len_0] = x - _len_0 = _len_0 + 1 - end - return _accum_0 -end)() +local k = { } +local _len_0 = 1 +for x in (function(...) + return print(...) +end)("hello") do + k[_len_0] = x + _len_0 = _len_0 + 1 +end local j = (function() local _accum_0 = { } - local _len_0 = 1 + local _len_1 = 1 for i = 1, 10 do - _accum_0[_len_0] = function(...) + _accum_0[_len_1] = function(...) return print(...) end - _len_0 = _len_0 + 1 + _len_1 = _len_1 + 1 end return _accum_0 end)() @@ -44,15 +41,15 @@ local m m = function(...) return (function(...) local _accum_0 = { } - local _len_0 = 1 + local _len_1 = 1 local _list_0 = { ... } for _index_0 = 1, #_list_0 do local x = _list_0[_index_0] if f(...) > 4 then - _accum_0[_len_0] = x - _len_0 = _len_0 + 1 + _accum_0[_len_1] = x + _len_1 = _len_1 + 1 end end return _accum_0 @@ -60,58 +57,52 @@ m = function(...) end local x = (function(...) local _accum_0 = { } - local _len_0 = 1 + local _len_1 = 1 local _list_0 = { ... } for _index_0 = 1, #_list_0 do local i = _list_0[_index_0] - _accum_0[_len_0] = i - _len_0 = _len_0 + 1 - end - return _accum_0 -end)(...) -local y = (function(...) - local _accum_0 = { } - local _len_0 = 1 - local _list_0 = { - ... - } - for _index_0 = 1, #_list_0 do - x = _list_0[_index_0] - _accum_0[_len_0] = x - _len_0 = _len_0 + 1 + _accum_0[_len_1] = i + _len_1 = _len_1 + 1 end return _accum_0 end)(...) -local z = (function(...) - local _accum_0 = { } - local _len_0 = 1 - for x in hallo do - if f(...) > 4 then - _accum_0[_len_0] = x - _len_0 = _len_0 + 1 - end +local y = { } +local _len_1 = 1 +local _list_0 = { + ... +} +for _index_0 = 1, #_list_0 do + x = _list_0[_index_0] + y[_len_1] = x + _len_1 = _len_1 + 1 +end +local z = { } +local _len_2 = 1 +for x in hallo do + if f(...) > 4 then + z[_len_2] = x + _len_2 = _len_2 + 1 end - return _accum_0 -end)(...) +end local a = (function(...) local _accum_0 = { } - local _len_0 = 1 + local _len_3 = 1 for i = 1, 10 do - _accum_0[_len_0] = ... - _len_0 = _len_0 + 1 + _accum_0[_len_3] = ... + _len_3 = _len_3 + 1 end return _accum_0 end)(...) local b = (function() local _accum_0 = { } - local _len_0 = 1 + local _len_3 = 1 for i = 1, 10 do - _accum_0[_len_0] = function() + _accum_0[_len_3] = function() return print(...) end - _len_0 = _len_0 + 1 + _len_3 = _len_3 + 1 end return _accum_0 end)() \ No newline at end of file diff --git a/spec/outputs/comprehension.lua b/spec/outputs/comprehension.lua index 4ac5530a..7224b8ec 100644 --- a/spec/outputs/comprehension.lua +++ b/spec/outputs/comprehension.lua @@ -79,79 +79,61 @@ _ = (function() end return _tbl_0 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 +local n1 = { } +local _len_0 = 1 +for i = 1, 10 do + n1[_len_0] = i + _len_0 = _len_0 + 1 +end +local n2 = { } +local _len_1 = 1 +for i = 1, 10 do + if i % 2 == 1 then + n2[_len_1] = i + _len_1 = _len_1 + 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 +local aa = { } +local _len_2 = 1 +for x = 1, 10 do + for y = 5, 14 do + aa[_len_2] = { + x, + y + } + _len_2 = _len_2 + 1 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 +local bb = { } +local _len_3 = 1 +for thing in y do + for i = 1, 10 do + bb[_len_3] = y + _len_3 = _len_3 + 1 end - return _accum_0 -end)() -local bb = (function() - local _accum_0 = { } - local _len_0 = 1 +end +local cc = { } +local _len_4 = 1 +for i = 1, 10 do for thing in y do - for i = 1, 10 do - _accum_0[_len_0] = y - _len_0 = _len_0 + 1 - end + cc[_len_4] = y + _len_4 = _len_4 + 1 end - return _accum_0 -end)() -local cc = (function() - local _accum_0 = { } - local _len_0 = 1 - for i = 1, 10 do +end +local dd = { } +local _len_5 = 1 +for i = 1, 10 do + if cool then 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 + if x > 3 then + if c + 3 then + dd[_len_5] = y + _len_5 = _len_5 + 1 end end end end - return _accum_0 -end)() +end _ = (function() local _tbl_0 = { } for i = 1, 10 do diff --git a/spec/outputs/lists.lua b/spec/outputs/lists.lua index e5ce5141..9566c908 100644 --- a/spec/outputs/lists.lua +++ b/spec/outputs/lists.lua @@ -1,17 +1,14 @@ -local hi = (function() - local _accum_0 = { } - local _len_0 = 1 - for _, x in ipairs({ - 1, - 2, - 3, - 4 - }) do - _accum_0[_len_0] = x * 2 - _len_0 = _len_0 + 1 - end - return _accum_0 -end)() +local hi = { } +local _len_0 = 1 +for _, x in ipairs({ + 1, + 2, + 3, + 4 +}) do + hi[_len_0] = x * 2 + _len_0 = _len_0 + 1 +end local items = { 1, 2, @@ -20,40 +17,34 @@ local items = { 5, 6 } -local mm = (function() - local _accum_0 = { } - local _len_0 = 1 - for self.x in ipairs(items) do - _accum_0[_len_0] = self.x - _len_0 = _len_0 + 1 - end - return _accum_0 -end)() +local mm = { } +local _len_1 = 1 +for self.x in ipairs(items) do + mm[_len_1] = self.x + _len_1 = _len_1 + 1 +end for z in ipairs(items) do if z > 4 then local _ = z end end -local rad = (function() - local _accum_0 = { } - local _len_0 = 1 - for a in ipairs({ - 1, - 2, - 3, - 4, - 5, - 6 - }) do - if good_number(a) then - _accum_0[_len_0] = { - a - } - _len_0 = _len_0 + 1 - end +local rad = { } +local _len_2 = 1 +for a in ipairs({ + 1, + 2, + 3, + 4, + 5, + 6 +}) do + if good_number(a) then + rad[_len_2] = { + a + } + _len_2 = _len_2 + 1 end - return _accum_0 -end)() +end for z in items do for j in list do if z > 4 then @@ -78,44 +69,41 @@ range = function(count) end dump((function() local _accum_0 = { } - local _len_0 = 1 + local _len_3 = 1 for x in range(10) do - _accum_0[_len_0] = x - _len_0 = _len_0 + 1 + _accum_0[_len_3] = x + _len_3 = _len_3 + 1 end return _accum_0 end)()) dump((function() local _accum_0 = { } - local _len_0 = 1 + local _len_3 = 1 for x in range(5) do if x > 2 then for y in range(5) do - _accum_0[_len_0] = { + _accum_0[_len_3] = { x, y } - _len_0 = _len_0 + 1 + _len_3 = _len_3 + 1 end end end return _accum_0 end)()) -local things = (function() - local _accum_0 = { } - local _len_0 = 1 - for x in range(10) do - if x > 5 then - for y in range(10) do - if y > 7 then - _accum_0[_len_0] = x + y - _len_0 = _len_0 + 1 - end +local things = { } +local _len_3 = 1 +for x in range(10) do + if x > 5 then + for y in range(10) do + if y > 7 then + things[_len_3] = x + y + _len_3 = _len_3 + 1 end end end - return _accum_0 -end)() +end for x in ipairs({ 1, 2, @@ -137,15 +125,12 @@ end for x in x do local _ = x end -local x = (function() - local _accum_0 = { } - local _len_0 = 1 - for x in x do - _accum_0[_len_0] = x - _len_0 = _len_0 + 1 - end - return _accum_0 -end)() +local x = { } +local _len_4 = 1 +for x in x do + x[_len_4] = x + _len_4 = _len_4 + 1 +end for x in ipairs({ 1, 2, @@ -161,45 +146,36 @@ for x in ipairs({ end end end -local double = (function() - local _accum_0 = { } - local _len_0 = 1 - for _index_0 = 1, #items do - x = items[_index_0] - _accum_0[_len_0] = x * 2 - _len_0 = _len_0 + 1 - end - return _accum_0 -end)() +local double = { } +local _len_5 = 1 +for _index_0 = 1, #items do + x = items[_index_0] + double[_len_5] = x * 2 + _len_5 = _len_5 + 1 +end for _index_0 = 1, #double do x = double[_index_0] print(x) end -local cut = (function() - local _accum_0 = { } - local _len_0 = 1 - for _index_0 = 1, #items do - x = items[_index_0] - if x > 3 then - _accum_0[_len_0] = x - _len_0 = _len_0 + 1 - end +local cut = { } +local _len_6 = 1 +for _index_0 = 1, #items do + x = items[_index_0] + if x > 3 then + cut[_len_6] = x + _len_6 = _len_6 + 1 end - return _accum_0 -end)() -local hello = (function() - local _accum_0 = { } - local _len_0 = 1 - for _index_0 = 1, #items do - x = items[_index_0] - for _index_1 = 1, #items do - local y = items[_index_1] - _accum_0[_len_0] = x + y - _len_0 = _len_0 + 1 - end +end +local hello = { } +local _len_7 = 1 +for _index_0 = 1, #items do + x = items[_index_0] + for _index_1 = 1, #items do + local y = items[_index_1] + hello[_len_7] = x + y + _len_7 = _len_7 + 1 end - return _accum_0 -end)() +end for _index_0 = 1, #hello do local z = hello[_index_0] print(z) @@ -251,10 +227,10 @@ local normal normal = function(hello) return (function() local _accum_0 = { } - local _len_0 = 1 + local _len_8 = 1 for x in yeah do - _accum_0[_len_0] = x - _len_0 = _len_0 + 1 + _accum_0[_len_8] = x + _len_8 = _len_8 + 1 end return _accum_0 end)() @@ -281,11 +257,11 @@ end return function() return (function() local _accum_0 = { } - local _len_0 = 1 + local _len_8 = 1 for _index_0 = 1, #things do x = things[_index_0] - _accum_0[_len_0] = x - _len_0 = _len_0 + 1 + _accum_0[_len_8] = x + _len_8 = _len_8 + 1 end return _accum_0 end)() From 39c280138aa7689847537849185e259e57977488 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Mon, 10 Jun 2013 19:58:18 -0700 Subject: [PATCH 116/554] rebuild! --- moonscript/compile/value.lua | 34 ++++++++++++++-------------------- moonscript/dump.lua | 17 +++++++---------- moonscript/errors.lua | 21 +++++++++------------ moonscript/transform.lua | 19 ++++++++----------- moonscript/util.lua | 27 ++++++++++++--------------- 5 files changed, 50 insertions(+), 68 deletions(-) diff --git a/moonscript/compile/value.lua b/moonscript/compile/value.lua index b0cab82e..0e6fad02 100644 --- a/moonscript/compile/value.lua +++ b/moonscript/compile/value.lua @@ -185,16 +185,13 @@ local value_compilers = { } }) end - local self_arg_values = (function() - local _accum_0 = { } - local _len_0 = 1 - for _index_0 = 1, #self_args do - local arg = self_args[_index_0] - _accum_0[_len_0] = arg[2] - _len_0 = _len_0 + 1 - end - return _accum_0 - end)() + local self_arg_values = { } + local _len_0 = 1 + for _index_0 = 1, #self_args do + local arg = self_args[_index_0] + self_arg_values[_len_0] = arg[2] + _len_0 = _len_0 + 1 + end if #self_args > 0 then _with_0:stm({ "assign", @@ -204,16 +201,13 @@ local value_compilers = { end _with_0:stms(block) if #args > #arg_names then - arg_names = (function() - local _accum_0 = { } - local _len_0 = 1 - for _index_0 = 1, #args do - local arg = args[_index_0] - _accum_0[_len_0] = arg[1] - _len_0 = _len_0 + 1 - end - return _accum_0 - end)() + arg_names = { } + local _len_1 = 1 + for _index_0 = 1, #args do + local arg = args[_index_0] + arg_names[_len_1] = arg[1] + _len_1 = _len_1 + 1 + end end _with_0.header = "function(" .. concat(arg_names, ", ") .. ")" return _with_0 diff --git a/moonscript/dump.lua b/moonscript/dump.lua index 5b5fea2a..3536babb 100644 --- a/moonscript/dump.lua +++ b/moonscript/dump.lua @@ -9,16 +9,13 @@ flat_value = function(op, depth) if type(op) ~= "table" then return tostring(op) end - local items = (function() - local _accum_0 = { } - local _len_0 = 1 - for _index_0 = 1, #op do - local item = op[_index_0] - _accum_0[_len_0] = flat_value(item, depth + 1) - _len_0 = _len_0 + 1 - end - return _accum_0 - end)() + local items = { } + local _len_0 = 1 + for _index_0 = 1, #op do + local item = op[_index_0] + items[_len_0] = flat_value(item, depth + 1) + _len_0 = _len_0 + 1 + end local pos = op[-1] return "{" .. (pos and "[" .. pos .. "] " or "") .. table.concat(items, ", ") .. "}" end diff --git a/moonscript/errors.lua b/moonscript/errors.lua index af3c98ed..83e701d0 100644 --- a/moonscript/errors.lua +++ b/moonscript/errors.lua @@ -42,18 +42,15 @@ truncate_traceback = function(traceback, chunk_func) end stop = stop - 1 end - traceback = (function() - local _accum_0 = { } - local _len_0 = 1 - local _list_0 = traceback - local _max_0 = stop - for _index_0 = 1, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do - local t = _list_0[_index_0] - _accum_0[_len_0] = t - _len_0 = _len_0 + 1 - end - return _accum_0 - end)() + traceback = { } + local _len_0 = 1 + local _list_0 = traceback + local _max_0 = stop + for _index_0 = 1, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do + local t = _list_0[_index_0] + traceback[_len_0] = t + _len_0 = _len_0 + 1 + end local rep = "function '" .. chunk_func .. "'" traceback[#traceback] = traceback[#traceback]:gsub(rep, "main chunk") return concat(traceback, "\n") diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 00d89fee..be339397 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -1109,17 +1109,14 @@ Statement = Transformer({ end return self:set("super", function(block, chain) if chain then - local slice = (function() - local _accum_0 = { } - local _len_0 = 1 - local _list_0 = chain - for _index_0 = 3, #_list_0 do - local item = _list_0[_index_0] - _accum_0[_len_0] = item - _len_0 = _len_0 + 1 - end - return _accum_0 - end)() + local slice = { } + local _len_0 = 1 + local _list_0 = chain + for _index_0 = 3, #_list_0 do + local item = _list_0[_index_0] + slice[_len_0] = item + _len_0 = _len_0 + 1 + end local new_chain = { "chain", parent_cls_name diff --git a/moonscript/util.lua b/moonscript/util.lua index 090a9d08..d0e6bb09 100644 --- a/moonscript/util.lua +++ b/moonscript/util.lua @@ -119,24 +119,21 @@ dump = function(what) end local debug_posmap debug_posmap = function(posmap, moon_code, lua_code) - local tuples = (function() - local _accum_0 = { } - local _len_0 = 1 - for k, v in pairs(posmap) do - _accum_0[_len_0] = { - k, - v - } - _len_0 = _len_0 + 1 - end - return _accum_0 - end)() + local tuples = { } + local _len_0 = 1 + for k, v in pairs(posmap) do + tuples[_len_0] = { + k, + v + } + _len_0 = _len_0 + 1 + end table.sort(tuples, function(a, b) return a[1] < b[1] end) local lines = (function() local _accum_0 = { } - local _len_0 = 1 + local _len_1 = 1 for _index_0 = 1, #tuples do local pair = tuples[_index_0] local lua_line, pos = unpack(pair) @@ -144,8 +141,8 @@ debug_posmap = function(posmap, moon_code, lua_code) local lua_text = get_line(lua_code, lua_line) local moon_text = get_closest_line(moon_code, moon_line) local _value_0 = tostring(pos) .. "\t " .. tostring(lua_line) .. ":[ " .. tostring(trim(lua_text)) .. " ] >> " .. tostring(moon_line) .. ":[ " .. tostring(trim(moon_text)) .. " ]" - _accum_0[_len_0] = _value_0 - _len_0 = _len_0 + 1 + _accum_0[_len_1] = _value_0 + _len_1 = _len_1 + 1 end return _accum_0 end)() From 3c7400dbd68c66cd448f859f03f1dccd39fcb141 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 19 Jun 2013 23:59:07 -0700 Subject: [PATCH 117/554] add class spec --- spec/class_spec.moon | 98 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 spec/class_spec.moon diff --git a/spec/class_spec.moon b/spec/class_spec.moon new file mode 100644 index 00000000..606a82fe --- /dev/null +++ b/spec/class_spec.moon @@ -0,0 +1,98 @@ + +describe "class", -> + it "should make a class with constructor", -> + class Thing + new: => + @color = "blue" + + instance = Thing! + + assert.same instance, { color: "blue" } + + it "should have instance methods", -> + class Thing + get_color: => @color + + new: => + @color = "blue" + + instance = Thing! + assert.same instance\get_color!, "blue" + + + it "should have class property", -> + class Thing + color: "blue" + get_color: => @color + + instance = Thing! + assert.same instance\get_color!, "blue" + assert.same Thing.color, "blue" + + it "should inherit another class", -> + class Base + get_property: => @[@property] + + new: (@property) => + + class Thing extends Base + color: "green" + + instance = Thing "color" + assert.same instance\get_property!, "green" + + it "should call super constructor", -> + class Base + new: (@property) => + + class Thing extends Base + new: (@name) => + super "name" + + instance = Thing "the_thing" + + assert.same instance.property, "name" + assert.same instance.name, "the_thing" + + + it "should call super method", -> + class Base + _count: 111 + counter: => @_count + + class Thing extends Base + counter: => "%08d"\format super! + + instance = Thing! + assert.same instance\counter!, "00000111" + + it "should get super class", -> + class Base + class Thing extends Base + get_super: => super + + instance = Thing! + assert.is_true instance\get_super! == Base + + it "should get a bound method from super", -> + class Base + count: 1 + get_count: => @count + + class Thing extends Base + get_count: => "this is wrong" + get_method: => super\get_count + + instance = Thing! + assert.same instance\get_method!!, 1 + + it "should have class properties", -> + class Base + class Thing extends Base + + instance = Thing! + + assert.same Base.__name, "Base" + assert.same Thing.__name, "Thing" + assert.is_true Thing.__parent == Base + From 34c065e7a89ad825bae269c308b9229ab24fb50a Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 20 Jun 2013 00:13:32 -0700 Subject: [PATCH 118/554] more class specs --- spec/class_spec.moon | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/spec/class_spec.moon b/spec/class_spec.moon index 606a82fe..c46b4415 100644 --- a/spec/class_spec.moon +++ b/spec/class_spec.moon @@ -96,3 +96,42 @@ describe "class", -> assert.same Thing.__name, "Thing" assert.is_true Thing.__parent == Base + assert.is_true instance.__class == Thing + + it "should have name when assigned", -> + Thing = class + assert.same Thing.__name, "Thing" + + + it "should not expose class properties on instance", -> + class Thing + @height: 10 + + Thing.color = "blue" + + instance = Thing! + assert.same instance.color, nil + assert.same instance.height, nil + + it "should expose new things added to __base", -> + class Thing + + instance = Thing! + Thing.__base.color = "green" + + assert.same instance.color, "green" + + it "should call with correct receiver", -> + local instance + + class Thing + is_class: => assert.is_true @ == Thing + is_instance: => assert.is_true @ == instance + + go: => + @@is_class! + @is_instance! + + instance = Thing! + instance\go! + From 3320ba20d4ceb857a0d1e028d382f42f3490b190 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 20 Jun 2013 08:28:05 -0700 Subject: [PATCH 119/554] let moon be included from current dir --- moon.lua | 1 + 1 file changed, 1 insertion(+) create mode 100644 moon.lua diff --git a/moon.lua b/moon.lua new file mode 100644 index 00000000..6b1536fd --- /dev/null +++ b/moon.lua @@ -0,0 +1 @@ +return require "moon.init" From f3d92e7b4ca2a667e40c35a3caccc11176c15d72 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 20 Jun 2013 09:21:46 -0700 Subject: [PATCH 120/554] comprehension spec --- spec/comprehension_spec.moon | 37 ++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 spec/comprehension_spec.moon diff --git a/spec/comprehension_spec.moon b/spec/comprehension_spec.moon new file mode 100644 index 00000000..901bcaa2 --- /dev/null +++ b/spec/comprehension_spec.moon @@ -0,0 +1,37 @@ + +describe "comprehension", -> + it "should double every number", -> + input = {1,2,3,4,5,6} + output_1 = [i * 2 for _, i in pairs input ] + output_2 = [i * 2 for i in *input ] + + assert.same output_1, {2,4,6,8,10,12} + + it "should create a slice", -> + input = {1,2,3,4,5,6} + + slice_1 = [i for i in *input[1,3]] + slice_2 = [i for i in *input[,3]] + + slice_3 = [i for i in *input[3,]] + slice_4 = [i for i in *input[,]] + + slice_5 = [i for i in *input[,,2]] + slice_6 = [i for i in *input[2,,2]] + + assert.same slice_1, {1,2,3} + assert.same slice_1, slice_2 + assert.same slice_3, {3,4,5,6} + assert.same slice_4, input + + assert.same slice_5, {1,3,5} + assert.same slice_6, {2,4,6} + + it "should be able to assign to self", -> + input = {1,2,3,4} + output = input + output = [i * 2 for i in *output] + + assert.same input, {1,2,3,4} + assert.same output, {2,4,6,8} + From fb270ad51627b947e1bae2d0fef15adedaa27861 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 21 Jun 2013 18:47:46 -0700 Subject: [PATCH 121/554] table comprehension spec --- spec/comprehension_spec.moon | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/spec/comprehension_spec.moon b/spec/comprehension_spec.moon index 901bcaa2..b7ac2270 100644 --- a/spec/comprehension_spec.moon +++ b/spec/comprehension_spec.moon @@ -35,3 +35,10 @@ describe "comprehension", -> assert.same input, {1,2,3,4} assert.same output, {2,4,6,8} + + it "should copy table", -> + input = { 1,2,3, hello: "world", thing: true } + output = {k,v for k,v in pairs input } + + assert.is_true input != output + assert.same input, output From 1b7f7ddd8d225cf98e8ca87224d7a68739130e0c Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 22 Jun 2013 23:16:21 -0700 Subject: [PATCH 122/554] destructure spec --- spec/destructure_spec.moon | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 spec/destructure_spec.moon diff --git a/spec/destructure_spec.moon b/spec/destructure_spec.moon new file mode 100644 index 00000000..fe300425 --- /dev/null +++ b/spec/destructure_spec.moon @@ -0,0 +1,32 @@ +describe "destructure", -> + it "should unpack array", -> + input = {1,2,3} + + {a,b,c} = {1,2,3} + {d,e,f} = input + + assert.same a, 1 + assert.same b, 2 + assert.same c, 3 + + assert.same d, 1 + assert.same e, 2 + assert.same f, 3 + + it "should destructure", -> + futurists = + sculptor: "Umberto Boccioni" + painter: "Vladimir Burliuk" + poet: + name: "F.T. Marinetti" + address: { + "Via Roma 42R" + "Bellagio, Italy 22021" + } + + {poet: {:name, address: {street, city}}} = futurists + + assert.same name, "F.T. Marinetti" + assert.same street, "Via Roma 42R" + assert.same city, "Bellagio, Italy 22021" + From 3a7f5503ce266dd685ea35a613c93a5f82d01545 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 25 Jun 2013 20:02:44 -0700 Subject: [PATCH 123/554] hide diff flag --- spec/lang_spec.moon | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/lang_spec.moon b/spec/lang_spec.moon index f0c72fd5..7fd1a3f8 100644 --- a/spec/lang_spec.moon +++ b/spec/lang_spec.moon @@ -72,6 +72,7 @@ diff_str = (expected, got) -> string_assert = (expected, got) -> if expected != got diff = diff_str expected, got + error "string equality assert failed" if os.getenv "HIDE_DIFF" error "string equality assert failed:\n" .. diff input_fname = (base) -> From a41637ba1e621806bef06b9ebb10f5e145505e5e Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 25 Jun 2013 20:05:20 -0700 Subject: [PATCH 124/554] don't generate unecessary code for classes --- moonscript/transform.lua | 177 +++++++------- moonscript/transform.moon | 76 +++--- spec/outputs/class.lua | 502 ++++++-------------------------------- spec/outputs/export.lua | 25 +- 4 files changed, 204 insertions(+), 576 deletions(-) diff --git a/moonscript/transform.lua b/moonscript/transform.lua index be339397..61a63223 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -888,6 +888,9 @@ Statement = Transformer({ end, class = function(self, node, ret, parent_assign) local _, name, parent_val, body = unpack(node) + if parent_val == "" then + parent_val = nil + end local statements = { } local properties = { } for _index_0 = 1, #body do @@ -939,30 +942,29 @@ Statement = Transformer({ local self_name = NameProxy("self") local cls_name = NameProxy("class") if not (constructor) then - constructor = build.fndef({ - args = { - { - "..." - } - }, - arrow = "fat", - body = { - build["if"]({ - cond = parent_cls_name, - ["then"] = { - build.chain({ - base = "super", + if parent_val then + constructor = build.fndef({ + args = { + { + "..." + } + }, + arrow = "fat", + body = { + build.chain({ + base = "super", + { + "call", { - "call", - { - "..." - } + "..." } - }) - } - }) - } - }) + } + }) + } + }) + else + constructor = build.fndef() + end end local real_name = name or parent_assign and parent_assign[2][1] local _exp_0 = ntype(real_name) @@ -1002,56 +1004,60 @@ Statement = Transformer({ "__name", real_name }, - { + parent_val and { "__parent", parent_cls_name - } - }) - local class_lookup = build["if"]({ - cond = { - "exp", - "val", - "==", - "nil", - "and", - parent_cls_name - }, - ["then"] = { - parent_cls_name:index("name") - } + } or nil }) - insert(class_lookup, { - "else", - { - "val" - } - }) - local cls_mt = build.table({ - { - "__index", - build.fndef({ - args = { - { - "cls" - }, - { - "name" - } + local class_index + if parent_val then + local class_lookup = build["if"]({ + cond = { + "exp", + "val", + "==", + "nil" + }, + ["then"] = { + parent_cls_name:index("name") + } + }) + insert(class_lookup, { + "else", + { + "val" + } + }) + class_index = build.fndef({ + args = { + { + "cls" }, - body = { - build.assign_one(LocalName("val"), build.chain({ - base = "rawget", + { + "name" + } + }, + body = { + build.assign_one(LocalName("val"), build.chain({ + base = "rawget", + { + "call", { - "call", - { - base_name, - "name" - } + base_name, + "name" } - })), - class_lookup - } - }) + } + })), + class_lookup + } + }) + else + class_index = base_name + end + local cls_mt = build.table({ + { + "__index", + class_index }, { "__call", @@ -1174,33 +1180,28 @@ Statement = Transformer({ "declare_glob", "*" }, - build.assign_one(parent_cls_name, parent_val == "" and "nil" or parent_val), + parent_val and build.assign_one(parent_cls_name, parent_val) or NOOP, build.assign_one(base_name, { "table", properties }), build.assign_one(base_name:chain("__index"), base_name), - build["if"]({ - cond = parent_cls_name, - ["then"] = { - build.chain({ - base = "setmetatable", - { - "call", + parent_val and build.chain({ + base = "setmetatable", + { + "call", + { + base_name, + build.chain({ + base = parent_cls_name, { - base_name, - build.chain({ - base = parent_cls_name, - { - "dot", - "__base" - } - }) + "dot", + "__base" } - } - }) + }) + } } - }), + }) or NOOP, build.assign_one(cls_name, cls), build.assign_one(base_name:chain("__class"), cls_name), build.group((function() @@ -1211,11 +1212,9 @@ Statement = Transformer({ } end end)()), - build["if"]({ + parent_val and build["if"]({ cond = { "exp", - parent_cls_name, - "and", parent_cls_name:chain("__inherited") }, ["then"] = { @@ -1227,7 +1226,7 @@ Statement = Transformer({ } }) } - }), + }) or NOOP, build.group((function() if name then return { diff --git a/moonscript/transform.moon b/moonscript/transform.moon index 07706b0b..801b5cf8 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -502,6 +502,7 @@ Statement = Transformer { class: (node, ret, parent_assign) => _, name, parent_val, body = unpack node + parent_val = nil if parent_val == "" -- split apart properties and statements statements = {} @@ -533,18 +534,16 @@ Statement = Transformer { cls_name = NameProxy "class" unless constructor - constructor = build.fndef { - args: {{"..."}} - arrow: "fat" - body: { - build["if"] { - cond: parent_cls_name - then: { - build.chain { base: "super", {"call", {"..."}} } - } + constructor = if parent_val + build.fndef { + args: {{"..."}} + arrow: "fat" + body: { + build.chain { base: "super", {"call", {"..."}} } } } - } + else + build.fndef! real_name = name or parent_assign and parent_assign[2][1] real_name = switch ntype real_name @@ -566,20 +565,20 @@ Statement = Transformer { {"__init", constructor} {"__base", base_name} {"__name", real_name} -- "quote the string" - {"__parent", parent_cls_name} + parent_val and {"__parent", parent_cls_name} or nil } - -- look up a name in the class object - class_lookup = build["if"] { - cond: {"exp", "val", "==", "nil", "and", parent_cls_name} - then: { - parent_cls_name\index"name" + -- looking up a name in the class object + class_index = if parent_val + class_lookup = build["if"] { + cond: { "exp", "val", "==", "nil" } + then: { + parent_cls_name\index"name" + } } - } - insert class_lookup, {"else", {"val"}} + insert class_lookup, {"else", {"val"}} - cls_mt = build.table { - {"__index", build.fndef { + build.fndef { args: {{"cls"}, {"name"}} body: { build.assign_one LocalName"val", build.chain { @@ -587,7 +586,12 @@ Statement = Transformer { } class_lookup } - }} + } + else + base_name + + cls_mt = build.table { + {"__index", class_index} {"__call", build.fndef { args: {{"cls"}, {"..."}} body: { @@ -651,22 +655,18 @@ Statement = Transformer { {"declare_glob", "*"} - .assign_one parent_cls_name, parent_val == "" and "nil" or parent_val + parent_val and .assign_one(parent_cls_name, parent_val) or NOOP + .assign_one base_name, {"table", properties} .assign_one base_name\chain"__index", base_name - .if { - cond: parent_cls_name - then: { - .chain { - base: "setmetatable" - {"call", { - base_name, - .chain { base: parent_cls_name, {"dot", "__base"}} - }} - } - } - } + parent_val and .chain({ + base: "setmetatable" + {"call", { + base_name, + .chain { base: parent_cls_name, {"dot", "__base"}} + }} + }) or NOOP .assign_one cls_name, cls .assign_one base_name\chain"__class", cls_name @@ -677,16 +677,14 @@ Statement = Transformer { } -- run the inherited callback - .if { - cond: {"exp", - parent_cls_name, "and", parent_cls_name\chain "__inherited" - } + parent_val and .if({ + cond: {"exp", parent_cls_name\chain "__inherited" } then: { parent_cls_name\chain "__inherited", {"call", { parent_cls_name, cls_name }} } - } + }) or NOOP .group if name then { .assign_one name, cls_name diff --git a/spec/outputs/class.lua b/spec/outputs/class.lua index e65b1910..1e3a3015 100644 --- a/spec/outputs/class.lua +++ b/spec/outputs/class.lua @@ -1,6 +1,5 @@ local Hello do - local _parent_0 = nil local _base_0 = { hello = function(self) return print(self.test, self.world) @@ -10,26 +9,15 @@ do end } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ __init = function(self, test, world) self.test, self.world = test, world return print("creating object..") end, __base = _base_0, - __name = "Hello", - __parent = _parent_0 + __name = "Hello" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -37,9 +25,6 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end Hello = _class_0 end local x = Hello(1, 2) @@ -47,34 +32,18 @@ x:hello() print(x) local Simple do - local _parent_0 = nil local _base_0 = { cool = function(self) return print("cool") end } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ - __init = function(self, ...) - if _parent_0 then - return _parent_0.__init(self, ...) - end - end, + __init = function() end, __base = _base_0, - __name = "Simple", - __parent = _parent_0 + __name = "Simple" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -82,9 +51,6 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end Simple = _class_0 end local Yikes @@ -92,9 +58,7 @@ do local _parent_0 = Simple local _base_0 = { } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end + setmetatable(_base_0, _parent_0.__base) local _class_0 = setmetatable({ __init = function(self) return print("created hello") @@ -105,7 +69,7 @@ do }, { __index = function(cls, name) local val = rawget(_base_0, name) - if val == nil and _parent_0 then + if val == nil then return _parent_0[name] else return val @@ -118,7 +82,7 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then + if _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end Yikes = _class_0 @@ -127,32 +91,20 @@ x = Yikes() x:cool() local Hi do - local _parent_0 = nil local _base_0 = { cool = function(self, num) return print("num", num) end } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ __init = function(self, arg) return print("init arg", arg) end, __base = _base_0, - __name = "Hi", - __parent = _parent_0 + __name = "Hi" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -160,9 +112,6 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end Hi = _class_0 end do @@ -173,9 +122,7 @@ do end } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end + setmetatable(_base_0, _parent_0.__base) local _class_0 = setmetatable({ __init = function(self) return _parent_0.__init(self, "man") @@ -186,7 +133,7 @@ do }, { __index = function(cls, name) local val = rawget(_base_0, name) - if val == nil and _parent_0 then + if val == nil then return _parent_0[name] else return val @@ -199,7 +146,7 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then + if _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end Simple = _class_0 @@ -209,32 +156,16 @@ x:cool() print(x.__class == Simple) local Okay do - local _parent_0 = nil local _base_0 = { something = 20323 } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ - __init = function(self, ...) - if _parent_0 then - return _parent_0.__init(self, ...) - end - end, + __init = function() end, __base = _base_0, - __name = "Okay", - __parent = _parent_0 + __name = "Okay" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -242,9 +173,6 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end Okay = _class_0 end local Biggie @@ -258,14 +186,10 @@ do end } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end + setmetatable(_base_0, _parent_0.__base) local _class_0 = setmetatable({ __init = function(self, ...) - if _parent_0 then - return _parent_0.__init(self, ...) - end + return _parent_0.__init(self, ...) end, __base = _base_0, __name = "Biggie", @@ -273,7 +197,7 @@ do }, { __index = function(cls, name) local val = rawget(_base_0, name) - if val == nil and _parent_0 then + if val == nil then return _parent_0[name] else return val @@ -286,41 +210,25 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then + if _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end Biggie = _class_0 end local Yeah do - local _parent_0 = nil local _base_0 = { okay = function(self) return _parent_0.something(self, 1, 2, 3, 4) end } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ - __init = function(self, ...) - if _parent_0 then - return _parent_0.__init(self, ...) - end - end, + __init = function() end, __base = _base_0, - __name = "Yeah", - __parent = _parent_0 + __name = "Yeah" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -328,41 +236,22 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end Yeah = _class_0 end local What do - local _parent_0 = nil local _base_0 = { something = function(self) return print("val:", self.val) end } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ - __init = function(self, ...) - if _parent_0 then - return _parent_0.__init(self, ...) - end - end, + __init = function() end, __base = _base_0, - __name = "What", - __parent = _parent_0 + __name = "What" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -370,9 +259,6 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end What = _class_0 end do @@ -390,14 +276,10 @@ do end } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end + setmetatable(_base_0, _parent_0.__base) local _class_0 = setmetatable({ __init = function(self, ...) - if _parent_0 then - return _parent_0.__init(self, ...) - end + return _parent_0.__init(self, ...) end, __base = _base_0, __name = "Hello", @@ -405,7 +287,7 @@ do }, { __index = function(cls, name) local val = rawget(_base_0, name) - if val == nil and _parent_0 then + if val == nil then return _parent_0[name] else return val @@ -418,7 +300,7 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then + if _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end Hello = _class_0 @@ -431,7 +313,6 @@ do end local CoolSuper do - local _parent_0 = nil local _base_0 = { hi = function(self) _parent_0.hi(self, 1, 2, 3, 4)(1, 2, 3, 4) @@ -444,27 +325,12 @@ do end } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ - __init = function(self, ...) - if _parent_0 then - return _parent_0.__init(self, ...) - end - end, + __init = function() end, __base = _base_0, - __name = "CoolSuper", - __parent = _parent_0 + __name = "CoolSuper" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -472,9 +338,6 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end CoolSuper = _class_0 end x = self.hello @@ -488,33 +351,17 @@ xx = function(hello, world, cool) end local ClassMan do - local _parent_0 = nil local _base_0 = { blue = function(self) end, green = function(self) end } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ - __init = function(self, ...) - if _parent_0 then - return _parent_0.__init(self, ...) - end - end, + __init = function() end, __base = _base_0, - __name = "ClassMan", - __parent = _parent_0 + __name = "ClassMan" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -527,9 +374,6 @@ do self.hello = 3434 self.world = 23423 self.red = function(self) end - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end ClassMan = _class_0 end x = self @@ -543,30 +387,14 @@ local _ = hello[self].world local Whacko do local hello - local _parent_0 = nil local _base_0 = { } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ - __init = function(self, ...) - if _parent_0 then - return _parent_0.__init(self, ...) - end - end, + __init = function() end, __base = _base_0, - __name = "Whacko", - __parent = _parent_0 + __name = "Whacko" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -584,9 +412,6 @@ do if something then print("yeah") end - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end Whacko = _class_0 end print("hello") @@ -594,30 +419,14 @@ local yyy yyy = function() local Cool do - local _parent_0 = nil local _base_0 = { } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ - __init = function(self, ...) - if _parent_0 then - return _parent_0.__init(self, ...) - end - end, + __init = function() end, __base = _base_0, - __name = "Cool", - __parent = _parent_0 + __name = "Cool" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -627,38 +436,19 @@ yyy = function() _base_0.__class = _class_0 local self = _class_0 _ = nil - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end Cool = _class_0 return _class_0 end end do - local _parent_0 = nil local _base_0 = { } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ - __init = function(self, ...) - if _parent_0 then - return _parent_0.__init(self, ...) - end - end, + __init = function() end, __base = _base_0, - __name = "D", - __parent = _parent_0 + __name = "D" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -668,36 +458,17 @@ do _base_0.__class = _class_0 local self = _class_0 _ = nil - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end a.b.c.D = _class_0 end do - local _parent_0 = nil local _base_0 = { } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ - __init = function(self, ...) - if _parent_0 then - return _parent_0.__init(self, ...) - end - end, + __init = function() end, __base = _base_0, - __name = "hello", - __parent = _parent_0 + __name = "hello" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -707,23 +478,16 @@ do _base_0.__class = _class_0 local self = _class_0 _ = nil - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end a.b["hello"] = _class_0 end do local _parent_0 = Hello.World local _base_0 = { } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end + setmetatable(_base_0, _parent_0.__base) local _class_0 = setmetatable({ __init = function(self, ...) - if _parent_0 then - return _parent_0.__init(self, ...) - end + return _parent_0.__init(self, ...) end, __base = _base_0, __name = "Something", @@ -731,7 +495,7 @@ do }, { __index = function(cls, name) local val = rawget(_base_0, name) - if val == nil and _parent_0 then + if val == nil then return _parent_0[name] else return val @@ -746,7 +510,7 @@ do _base_0.__class = _class_0 local self = _class_0 _ = nil - if _parent_0 and _parent_0.__inherited then + if _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end (function() @@ -755,30 +519,14 @@ do end local a do - local _parent_0 = nil local _base_0 = { } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ - __init = function(self, ...) - if _parent_0 then - return _parent_0.__init(self, ...) - end - end, + __init = function() end, __base = _base_0, - __name = "a", - __parent = _parent_0 + __name = "a" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -786,38 +534,19 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end a = _class_0 end local b local Something do - local _parent_0 = nil local _base_0 = { } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ - __init = function(self, ...) - if _parent_0 then - return _parent_0.__init(self, ...) - end - end, + __init = function() end, __base = _base_0, - __name = "Something", - __parent = _parent_0 + __name = "Something" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -825,9 +554,6 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end Something = _class_0 b = _class_0 end @@ -836,14 +562,10 @@ do local _parent_0 = Hello local _base_0 = { } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end + setmetatable(_base_0, _parent_0.__base) local _class_0 = setmetatable({ __init = function(self, ...) - if _parent_0 then - return _parent_0.__init(self, ...) - end + return _parent_0.__init(self, ...) end, __base = _base_0, __name = "Something", @@ -851,7 +573,7 @@ do }, { __index = function(cls, name) local val = rawget(_base_0, name) - if val == nil and _parent_0 then + if val == nil then return _parent_0[name] else return val @@ -864,7 +586,7 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then + if _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end Something = _class_0 @@ -875,14 +597,10 @@ do local _parent_0 = World local _base_0 = { } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end + setmetatable(_base_0, _parent_0.__base) local _class_0 = setmetatable({ __init = function(self, ...) - if _parent_0 then - return _parent_0.__init(self, ...) - end + return _parent_0.__init(self, ...) end, __base = _base_0, __name = "d", @@ -890,7 +608,7 @@ do }, { __index = function(cls, name) local val = rawget(_base_0, name) - if val == nil and _parent_0 then + if val == nil then return _parent_0[name] else return val @@ -903,7 +621,7 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then + if _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end d = _class_0 @@ -911,30 +629,14 @@ end print(((function() local WhatsUp do - local _parent_0 = nil local _base_0 = { } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ - __init = function(self, ...) - if _parent_0 then - return _parent_0.__init(self, ...) - end - end, + __init = function() end, __base = _base_0, - __name = "WhatsUp", - __parent = _parent_0 + __name = "WhatsUp" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -942,38 +644,19 @@ print(((function() end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end WhatsUp = _class_0 return _class_0 end end)()).__name) do - local _parent_0 = nil local _base_0 = { } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ - __init = function(self, ...) - if _parent_0 then - return _parent_0.__init(self, ...) - end - end, + __init = function() end, __base = _base_0, - __name = "Something", - __parent = _parent_0 + __name = "Something" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -983,35 +666,20 @@ do _base_0.__class = _class_0 local self = _class_0 _ = nil - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end Something = _class_0 end do local val, insert - local _parent_0 = nil local _base_0 = { } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ __init = function(self) return print(insert, val) end, __base = _base_0, - __name = "Something", - __parent = _parent_0 + __name = "Something" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -1025,32 +693,17 @@ do local _obj_0 = table insert = _obj_0.insert end - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end Something = _class_0 end do - local _parent_0 = nil local _base_0 = { } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ __init = hi, __base = _base_0, - __name = "X", - __parent = _parent_0 + __name = "X" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -1058,9 +711,6 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end X = _class_0 end return nil \ No newline at end of file diff --git a/spec/outputs/export.lua b/spec/outputs/export.lua index 20b7531e..72ebadea 100644 --- a/spec/outputs/export.lua +++ b/spec/outputs/export.lua @@ -4,32 +4,16 @@ do end do do - local _parent_0 = nil local _base_0 = { umm = "cool" } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ - __init = function(self, ...) - if _parent_0 then - return _parent_0.__init(self, ...) - end - end, + __init = function() end, __base = _base_0, - __name = "Something", - __parent = _parent_0 + __name = "Something" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -37,9 +21,6 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end Something = _class_0 end end From 9a6619214db20cde35db4adc265e2b3b989cc2f7 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 25 Jun 2013 20:06:56 -0700 Subject: [PATCH 125/554] rebuild :cat: --- moonscript/compile.lua | 90 +++++----------------------------- moonscript/data.lua | 19 +------ moonscript/transform.lua | 57 +++------------------ moonscript/transform/names.lua | 38 ++------------ 4 files changed, 24 insertions(+), 180 deletions(-) diff --git a/moonscript/compile.lua b/moonscript/compile.lua index be64604c..d7709085 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -32,7 +32,6 @@ local mtype = util.moon.type local indent_char = " " local Line, DelayedLine, Lines, Block, RootBlock do - local _parent_0 = nil local _base_0 = { mark_pos = function(self, pos, line) if line == nil then @@ -133,25 +132,14 @@ do end } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ __init = function(self) self.posmap = { } end, __base = _base_0, - __name = "Lines", - __parent = _parent_0 + __name = "Lines" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -159,13 +147,9 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end Lines = _class_0 end do - local _parent_0 = nil local _base_0 = { pos = nil, _append_single = function(self, item) @@ -237,27 +221,12 @@ do end } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ - __init = function(self, ...) - if _parent_0 then - return _parent_0.__init(self, ...) - end - end, + __init = function() end, __base = _base_0, - __name = "Line", - __parent = _parent_0 + __name = "Line" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -265,13 +234,9 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end Line = _class_0 end do - local _parent_0 = nil local _base_0 = { prepare = function() end, render = function(self) @@ -280,25 +245,14 @@ do end } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ __init = function(self, fn) self.prepare = fn end, __base = _base_0, - __name = "DelayedLine", - __parent = _parent_0 + __name = "DelayedLine" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -306,13 +260,9 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end DelayedLine = _class_0 end do - local _parent_0 = nil local _base_0 = { header = "do", footer = "end", @@ -608,9 +558,6 @@ do end } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ __init = function(self, parent, header, footer) self.parent, self.header, self.footer = parent, header, footer @@ -638,17 +585,9 @@ do end end, __base = _base_0, - __name = "Block", - __parent = _parent_0 + __name = "Block" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -656,9 +595,6 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end Block = _class_0 end do @@ -682,9 +618,7 @@ do end } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end + setmetatable(_base_0, _parent_0.__base) local _class_0 = setmetatable({ __init = function(self, options) self.options = options @@ -697,7 +631,7 @@ do }, { __index = function(cls, name) local val = rawget(_base_0, name) - if val == nil and _parent_0 then + if val == nil then return _parent_0[name] else return val @@ -710,7 +644,7 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then + if _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end RootBlock = _class_0 diff --git a/moonscript/data.lua b/moonscript/data.lua index a2e99fb3..83be3a88 100644 --- a/moonscript/data.lua +++ b/moonscript/data.lua @@ -10,7 +10,6 @@ Set = function(items) end local Stack do - local _parent_0 = nil local _base_0 = { __tostring = function(self) return "" @@ -27,9 +26,6 @@ do end } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ __init = function(self, ...) local _list_0 = { @@ -42,17 +38,9 @@ do return nil end, __base = _base_0, - __name = "Stack", - __parent = _parent_0 + __name = "Stack" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -60,9 +48,6 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end Stack = _class_0 end local lua_keywords = Set({ diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 61a63223..6910307d 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -15,33 +15,21 @@ local NOOP = { } local Run, apply_to_last, is_singular, extract_declarations, expand_elseif_assign, constructor_name, with_continue_listener, Transformer, construct_comprehension, Statement, Accumulator, default_accumulator, implicitly_return, Value do - local _parent_0 = nil local _base_0 = { call = function(self, state) return self.fn(state) end } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ __init = function(self, fn) self.fn = fn self[1] = "run" end, __base = _base_0, - __name = "Run", - __parent = _parent_0 + __name = "Run" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -49,9 +37,6 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end Run = _class_0 end apply_to_last = function(stms, fn) @@ -218,7 +203,6 @@ with_continue_listener = function(body) } end do - local _parent_0 = nil local _base_0 = { transform = function(self, scope, node, ...) if self.seen_nodes[node] then @@ -253,9 +237,6 @@ do end } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ __init = function(self, transformers) self.transformers = transformers @@ -264,17 +245,9 @@ do }) end, __base = _base_0, - __name = "Transformer", - __parent = _parent_0 + __name = "Transformer" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -282,9 +255,6 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end Transformer = _class_0 end construct_comprehension = function(inner, clauses) @@ -1259,7 +1229,6 @@ Statement = Transformer({ end }) do - local _parent_0 = nil local _base_0 = { body_idx = { ["for"] = 4, @@ -1320,9 +1289,6 @@ do end } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ __init = function(self, accum_name) self.accum_name = accum_name or NameProxy("accum") @@ -1330,17 +1296,9 @@ do self.len_name = NameProxy("len") end, __base = _base_0, - __name = "Accumulator", - __parent = _parent_0 + __name = "Accumulator" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -1348,9 +1306,6 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end Accumulator = _class_0 end default_accumulator = function(self, node) diff --git a/moonscript/transform/names.lua b/moonscript/transform/names.lua index 5f439201..4d596bd3 100644 --- a/moonscript/transform/names.lua +++ b/moonscript/transform/names.lua @@ -10,33 +10,21 @@ do end local LocalName do - local _parent_0 = nil local _base_0 = { get_name = function(self) return self.name end } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ __init = function(self, name) self.name = name self[1] = "temp_name" end, __base = _base_0, - __name = "LocalName", - __parent = _parent_0 + __name = "LocalName" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -44,14 +32,10 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end LocalName = _class_0 end local NameProxy do - local _parent_0 = nil local _base_0 = { get_name = function(self, scope, dont_put) if dont_put == nil then @@ -106,26 +90,15 @@ do end } _base_0.__index = _base_0 - if _parent_0 then - setmetatable(_base_0, _parent_0.__base) - end local _class_0 = setmetatable({ __init = function(self, prefix) self.prefix = prefix self[1] = "temp_name" end, __base = _base_0, - __name = "NameProxy", - __parent = _parent_0 + __name = "NameProxy" }, { - __index = function(cls, name) - local val = rawget(_base_0, name) - if val == nil and _parent_0 then - return _parent_0[name] - else - return val - end - end, + __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -133,9 +106,6 @@ do end }) _base_0.__class = _class_0 - if _parent_0 and _parent_0.__inherited then - _parent_0.__inherited(_parent_0, _class_0) - end NameProxy = _class_0 end return { From 1fa83e1e9c5a809c07275d9cec931066538584c6 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 28 Jun 2013 23:17:23 -0700 Subject: [PATCH 126/554] copy value before making accumlator for unpack foreach --- moonscript/compile/value.lua | 2 +- moonscript/errors.lua | 2 +- moonscript/transform.lua | 31 ++++++++++++++++++++++++------- moonscript/transform.moon | 19 ++++++++++++++----- moonscript/types.lua | 10 +++++++--- moonscript/types.moon | 6 +++--- spec/outputs/bubbling.lua | 8 ++++---- thoughts | 1 + 8 files changed, 55 insertions(+), 24 deletions(-) diff --git a/moonscript/compile/value.lua b/moonscript/compile/value.lua index 0e6fad02..f4352ea2 100644 --- a/moonscript/compile/value.lua +++ b/moonscript/compile/value.lua @@ -46,9 +46,9 @@ local value_compilers = { do local _with_0 = self:line() _with_0:append_list((function() + local _list_0 = node local _accum_0 = { } local _len_0 = 1 - local _list_0 = node for _index_0 = 2, #_list_0 do local v = _list_0[_index_0] _accum_0[_len_0] = self:value(v) diff --git a/moonscript/errors.lua b/moonscript/errors.lua index 83e701d0..e36780cc 100644 --- a/moonscript/errors.lua +++ b/moonscript/errors.lua @@ -42,9 +42,9 @@ truncate_traceback = function(traceback, chunk_func) end stop = stop - 1 end + local _list_0 = traceback traceback = { } local _len_0 = 1 - local _list_0 = traceback local _max_0 = stop for _index_0 = 1, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do local t = _list_0[_index_0] diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 6910307d..dd0351d1 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -349,11 +349,13 @@ Statement = Transformer({ if "comprehension" == _exp_0 then local first_name = names[1] local a = Accumulator(first_name) - node = self.transform.statement(first_value, function(exp) + local action + action = function(exp) return a:mutate_body({ exp }) - end) + end + node = self.transform.statement(first_value, action, node) return a:wrap(node, "group") end end @@ -585,9 +587,9 @@ Statement = Transformer({ wrapped = build.group({ build.declare({ names = (function() + local _list_0 = stm[2] local _accum_0 = { } local _len_0 = 1 - local _list_0 = stm[2] for _index_0 = 1, #_list_0 do local name = _list_0[_index_0] if type(name) == "string" then @@ -699,7 +701,7 @@ Statement = Transformer({ end)() }) end, - foreach = function(self, node) + foreach = function(self, node, _, parent_assign) smart_node(node) local source = unpack(node.iter) local destructures = { } @@ -727,7 +729,11 @@ Statement = Transformer({ if ntype(source) == "unpack" then local list = source[2] local index_name = NameProxy("index") - local list_name = self:is_local(list) and list or NameProxy("list") + local assign_name + if parent_assign then + assign_name = parent_assign[2][1] + end + local list_name = assign_name ~= list and self:is_local(list) and list or NameProxy("list") local slice_var = nil local bounds if is_slice(list) then @@ -768,7 +774,7 @@ Statement = Transformer({ } } end - return build.group({ + local out = build.group({ list_name ~= list and build.assign_one(list_name, list) or NOOP, slice_var or NOOP, build["for"]({ @@ -786,6 +792,8 @@ Statement = Transformer({ } }) }) + out.has_unpack_copy = true + return out end node.body = with_continue_listener(node.body) end, @@ -1085,9 +1093,9 @@ Statement = Transformer({ end return self:set("super", function(block, chain) if chain then + local _list_0 = chain local slice = { } local _len_0 = 1 - local _list_0 = chain for _index_0 = 3, #_list_0 do local item = _list_0[_index_0] slice[_len_0] = item @@ -1244,7 +1252,16 @@ do if group_type == nil then group_type = "block_exp" end + local copy_list + if rawget(node, "has_unpack_copy") then + do + local _with_0 = node[2][1] + node[2][1] = NOOP + copy_list = _with_0 + end + end return build[group_type]({ + copy_list or NOOP, build.assign_one(self.accum_name, build.table()), build.assign_one(self.len_name, 1), node, diff --git a/moonscript/transform.moon b/moonscript/transform.moon index 801b5cf8..92bc4412 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -181,8 +181,8 @@ Statement = Transformer { first_name = names[1] a = Accumulator first_name - node = @transform.statement first_value, (exp) -> - a\mutate_body { exp } + action = (exp) -> a\mutate_body { exp } + node = @transform.statement first_value, action, node return a\wrap node, "group" @@ -389,7 +389,7 @@ Statement = Transformer { ret scope_name } - foreach: (node) => + foreach: (node, _, parent_assign) => smart_node node source = unpack node.iter @@ -409,7 +409,8 @@ Statement = Transformer { list = source[2] index_name = NameProxy "index" - list_name = @is_local(list) and list or NameProxy "list" + assign_name = parent_assign[2][1] if parent_assign + list_name = assign_name != list and @is_local(list) and list or NameProxy "list" slice_var = nil bounds = if is_slice list @@ -430,7 +431,7 @@ Statement = Transformer { else {1, {"length", list_name}} - return build.group { + out = build.group { list_name != list and build.assign_one(list_name, list) or NOOP slice_var or NOOP build["for"] { @@ -443,6 +444,9 @@ Statement = Transformer { } } + out.has_unpack_copy = true + return out + node.body = with_continue_listener node.body while: (node) => @@ -721,7 +725,12 @@ class Accumulator -- wrap the node into a block_exp wrap: (node, group_type="block_exp") => + copy_list = if rawget node, "has_unpack_copy" + with node[2][1] + node[2][1] = NOOP + build[group_type] { + copy_list or NOOP build.assign_one @accum_name, build.table! build.assign_one @len_name, 1 node diff --git a/moonscript/types.lua b/moonscript/types.lua index 4a171a25..a6d70fa6 100644 --- a/moonscript/types.lua +++ b/moonscript/types.lua @@ -1,14 +1,18 @@ local util = require("moonscript.util") -local data = require("moonscript.data") +local Set +do + local _table_0 = require("moonscript.data") + Set = _table_0.Set +end local insert = table.insert local unpack = util.unpack -local manual_return = data.Set({ +local manual_return = Set({ "foreach", "for", "while", "return" }) -local cascading = data.Set({ +local cascading = Set({ "if", "unless", "with", diff --git a/moonscript/types.moon b/moonscript/types.moon index 992ff779..e603f602 100644 --- a/moonscript/types.moon +++ b/moonscript/types.moon @@ -1,17 +1,17 @@ util = require "moonscript.util" -data = require "moonscript.data" +import Set from require "moonscript.data" import insert from table import unpack from util -- implicit return does not work on these statements -manual_return = data.Set{"foreach", "for", "while", "return"} +manual_return = Set{"foreach", "for", "while", "return"} -- Assigns and returns are bubbled into their bodies. -- All cascading statement transform functions accept a second arugment that -- is the transformation to apply to the last statement in their body -cascading = data.Set{ "if", "unless", "with", "switch", "class", "do" } +cascading = Set{ "if", "unless", "with", "switch", "class", "do" } -- type of node as string ntype = (node) -> diff --git a/spec/outputs/bubbling.lua b/spec/outputs/bubbling.lua index 4d83336f..38c0757b 100644 --- a/spec/outputs/bubbling.lua +++ b/spec/outputs/bubbling.lua @@ -40,11 +40,11 @@ end)() local m m = function(...) return (function(...) - local _accum_0 = { } - local _len_1 = 1 local _list_0 = { ... } + local _accum_0 = { } + local _len_1 = 1 for _index_0 = 1, #_list_0 do local x = _list_0[_index_0] if f(...) > 4 then @@ -68,11 +68,11 @@ local x = (function(...) end return _accum_0 end)(...) -local y = { } -local _len_1 = 1 local _list_0 = { ... } +local y = { } +local _len_1 = 1 for _index_0 = 1, #_list_0 do x = _list_0[_index_0] y[_len_1] = x diff --git a/thoughts b/thoughts index ae5ecb94..735f6684 100644 --- a/thoughts +++ b/thoughts @@ -37,4 +37,5 @@ x = for thing in *things if is_important thing break thing +-- all function literals have a string that is their function definition From 347b427266ded384a2d2eaa1d35e88216580d179 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 29 Jun 2013 01:09:42 -0700 Subject: [PATCH 127/554] import is backed by destructure --- moonscript/transform.lua | 89 ++++++++------------------- moonscript/transform.moon | 31 +++------- moonscript/transform/destructure.lua | 14 +++-- moonscript/transform/destructure.moon | 9 ++- spec/outputs/import.lua | 69 ++++++++++++++------- 5 files changed, 97 insertions(+), 115 deletions(-) diff --git a/moonscript/transform.lua b/moonscript/transform.lua index dd0351d1..caa773c9 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -456,78 +456,43 @@ Statement = Transformer({ end, import = function(self, node) local _, names, source = unpack(node) - local stubs = (function() + local table_values = (function() local _accum_0 = { } local _len_0 = 1 for _index_0 = 1, #names do local name = names[_index_0] - if type(name) == "table" then - _accum_0[_len_0] = name + local dest_val + if ntype(name) == "colon_stub" then + dest_val = name[2] else - _accum_0[_len_0] = { - "dot", - name - } + dest_val = name end + local _value_0 = { + { + "key_literal", + name + }, + dest_val + } + _accum_0[_len_0] = _value_0 _len_0 = _len_0 + 1 end return _accum_0 end)() - local real_names = (function() - local _accum_0 = { } - local _len_0 = 1 - for _index_0 = 1, #names do - local name = names[_index_0] - _accum_0[_len_0] = type(name) == "table" and name[2] or name - _len_0 = _len_0 + 1 - end - return _accum_0 - end)() - if type(source) == "string" then - return build.assign({ - names = real_names, - values = (function() - local _accum_0 = { } - local _len_0 = 1 - for _index_0 = 1, #stubs do - local stub = stubs[_index_0] - _accum_0[_len_0] = build.chain({ - base = source, - stub - }) - _len_0 = _len_0 + 1 - end - return _accum_0 - end)() - }) - else - local source_name = NameProxy("table") - return build.group({ - { - "declare", - real_names - }, - build["do"]({ - build.assign_one(source_name, source), - build.assign({ - names = real_names, - values = (function() - local _accum_0 = { } - local _len_0 = 1 - for _index_0 = 1, #stubs do - local stub = stubs[_index_0] - _accum_0[_len_0] = build.chain({ - base = source_name, - stub - }) - _len_0 = _len_0 + 1 - end - return _accum_0 - end)() - }) - }) - }) - end + local dest = { + "table", + table_values + } + return { + "assign", + { + dest + }, + { + source + }, + [-1] = node[-1] + } end, comprehension = function(self, node, action) local _, exp, clauses = unpack(node) diff --git a/moonscript/transform.moon b/moonscript/transform.moon index 92bc4412..c6501b0d 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -251,33 +251,16 @@ Statement = Transformer { import: (node) => _, names, source = unpack node - - stubs = for name in *names - if type(name) == "table" - name + table_values = for name in *names + dest_val = if ntype(name) == "colon_stub" + name[2] else - {"dot", name} + name - real_names = for name in *names - type(name) == "table" and name[2] or name + {{"key_literal", name}, dest_val} - if type(source) == "string" - build.assign { - names: real_names - values: [build.chain { base: source, stub} for stub in *stubs] - } - else - source_name = NameProxy "table" - build.group { - {"declare", real_names} - build["do"] { - build.assign_one source_name, source - build.assign { - names: real_names - values: [build.chain { base: source_name, stub} for stub in *stubs] - } - } - } + dest = { "table", table_values } + { "assign", {dest}, {source}, [-1]: node[-1] } comprehension: (node, action) => _, exp, clauses = unpack node diff --git a/moonscript/transform/destructure.lua b/moonscript/transform/destructure.lua index 7ad4b4ed..2cb88978 100644 --- a/moonscript/transform/destructure.lua +++ b/moonscript/transform/destructure.lua @@ -19,6 +19,7 @@ do local _table_0 = require("moonscript.errors") user_error = _table_0.user_error end +local util = require("moonscript.util") local join join = function(...) do @@ -75,10 +76,15 @@ extract_assign_names = function(name, accum, prefix) local key = tuple[1] local s if ntype(key) == "key_literal" then - s = { - "dot", - key[2] - } + local key_name = key[2] + if ntype(key_name) == "colon_stub" then + s = key_name + else + s = { + "dot", + key_name + } + end else s = { "index", diff --git a/moonscript/transform/destructure.moon b/moonscript/transform/destructure.moon index df20bbbf..7175854f 100644 --- a/moonscript/transform/destructure.moon +++ b/moonscript/transform/destructure.moon @@ -6,6 +6,8 @@ import unpack from require "moonscript.util" import user_error from require "moonscript.errors" +util = require "moonscript.util" + join = (...) -> with out = {} i = 1 @@ -29,7 +31,11 @@ extract_assign_names = (name, accum={}, prefix={}) -> else key = tuple[1] s = if ntype(key) == "key_literal" - {"dot", key[2]} + key_name = key[2] + if ntype(key_name) == "colon_stub" + key_name + else + {"dot", key_name} else {"index", key} @@ -67,7 +73,6 @@ build_assign = (scope, destruct_literal, receiver) -> for tuple in *extracted_names insert names, tuple[1] insert values, NameProxy.chain obj, unpack tuple[2] - -- insert values, obj\chain unpack tuple[2] build.group { {"declare", names} diff --git a/spec/outputs/import.lua b/spec/outputs/import.lua index 1bd218e4..f7467f4f 100644 --- a/spec/outputs/import.lua +++ b/spec/outputs/import.lua @@ -1,21 +1,29 @@ -local hello = yeah.hello +local hello +do + local _obj_0 = yeah + hello = _obj_0.hello +end local world do - local _table_0 = table["cool"] - hello, world = _table_0.hello, _table_0.world + local _obj_0 = table["cool"] + hello, world = _obj_0.hello, _obj_0.world +end +local a, b, c +do + local _obj_0 = items + a, b, c = _obj_0.a, (function() + local _base_0 = _obj_0 + local _fn_0 = _base_0.b + return function(...) + return _fn_0(_base_0, ...) + end + end)(), _obj_0.c end -local a, b, c = items.a, (function() - local _base_0 = items - local _fn_0 = _base_0.b - return function(...) - return _fn_0(_base_0, ...) - end -end)(), items.c local master, ghost do - local _table_0 = find("mytable") - master, ghost = _table_0.master, (function() - local _base_0 = _table_0 + local _obj_0 = find("mytable") + master, ghost = _obj_0.master, (function() + local _base_0 = _obj_0 local _fn_0 = _base_0.ghost return function(...) return _fn_0(_base_0, ...) @@ -27,15 +35,15 @@ a, yumm = 3434, "hello" local _table_0 = 232 local something do - local _table_1 = a(table) - something = _table_1.something + local _obj_0 = a(table) + something = _obj_0.something end if indent then local okay, well do - local _table_1 = tables[100] - okay, well = _table_1.okay, (function() - local _base_0 = _table_1 + local _obj_0 = tables[100] + okay, well = _obj_0.okay, (function() + local _base_0 = _obj_0 local _fn_0 = _base_0.well return function(...) return _fn_0(_base_0, ...) @@ -44,17 +52,32 @@ if indent then end end do - a, b, c = z.a, z.b, z.c + do + local _obj_0 = z + a, b, c = _obj_0.a, _obj_0.b, _obj_0.c + end end do - a, b, c = z.a, z.b, z.c + do + local _obj_0 = z + a, b, c = _obj_0.a, _obj_0.b, _obj_0.c + end end do - a, b, c = z.a, z.b, z.c + do + local _obj_0 = z + a, b, c = _obj_0.a, _obj_0.b, _obj_0.c + end end do - a, b, c = z.a, z.b, z.c + do + local _obj_0 = z + a, b, c = _obj_0.a, _obj_0.b, _obj_0.c + end end do - a, b, c = z.a, z.b, z.c + do + local _obj_0 = z + a, b, c = _obj_0.a, _obj_0.b, _obj_0.c + end end \ No newline at end of file From d378e218e82078fab935e9abcd79b9f16569f498 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 29 Jun 2013 08:15:28 -0700 Subject: [PATCH 128/554] rebuild for import updates --- moonscript/compile.lua | 29 ++++++++++++++++------------ moonscript/compile/statement.lua | 13 +++++++++---- moonscript/compile/value.lua | 17 ++++++++++------ moonscript/data.lua | 6 +++++- moonscript/errors.lua | 12 +++++++++--- moonscript/init.lua | 10 +++++++--- moonscript/transform.lua | 16 ++++++++++----- moonscript/transform/destructure.lua | 22 ++++++++++++--------- moonscript/transform/names.lua | 8 ++++---- moonscript/types.lua | 13 +++++++++---- moonscript/util.lua | 6 +++++- 11 files changed, 100 insertions(+), 52 deletions(-) diff --git a/moonscript/compile.lua b/moonscript/compile.lua index d7709085..561e822f 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -3,31 +3,36 @@ local dump = require("moonscript.dump") local transform = require("moonscript.transform") local NameProxy, LocalName do - local _table_0 = require("moonscript.transform.names") - NameProxy, LocalName = _table_0.NameProxy, _table_0.LocalName + local _obj_0 = require("moonscript.transform.names") + NameProxy, LocalName = _obj_0.NameProxy, _obj_0.LocalName end local Set do - local _table_0 = require("moonscript.data") - Set = _table_0.Set + local _obj_0 = require("moonscript.data") + Set = _obj_0.Set end local ntype, has_value do - local _table_0 = require("moonscript.types") - ntype, has_value = _table_0.ntype, _table_0.has_value + local _obj_0 = require("moonscript.types") + ntype, has_value = _obj_0.ntype, _obj_0.has_value end local statement_compilers do - local _table_0 = require("moonscript.compile.statement") - statement_compilers = _table_0.statement_compilers + local _obj_0 = require("moonscript.compile.statement") + statement_compilers = _obj_0.statement_compilers end local value_compilers do - local _table_0 = require("moonscript.compile.value") - value_compilers = _table_0.value_compilers + local _obj_0 = require("moonscript.compile.value") + value_compilers = _obj_0.value_compilers end -local concat, insert = table.concat, table.insert -local pos_to_line, get_closest_line, trim, unpack = util.pos_to_line, util.get_closest_line, util.trim, util.unpack +local concat, insert +do + local _obj_0 = table + concat, insert = _obj_0.concat, _obj_0.insert +end +local pos_to_line, get_closest_line, trim, unpack +pos_to_line, get_closest_line, trim, unpack = util.pos_to_line, util.get_closest_line, util.trim, util.unpack local mtype = util.moon.type local indent_char = " " local Line, DelayedLine, Lines, Block, RootBlock diff --git a/moonscript/compile/statement.lua b/moonscript/compile/statement.lua index b7519487..bf858070 100644 --- a/moonscript/compile/statement.lua +++ b/moonscript/compile/statement.lua @@ -1,12 +1,17 @@ local util = require("moonscript.util") local data = require("moonscript.data") -local reversed, unpack = util.reversed, util.unpack +local reversed, unpack +reversed, unpack = util.reversed, util.unpack local ntype do - local _table_0 = require("moonscript.types") - ntype = _table_0.ntype + local _obj_0 = require("moonscript.types") + ntype = _obj_0.ntype +end +local concat, insert +do + local _obj_0 = table + concat, insert = _obj_0.concat, _obj_0.insert end -local concat, insert = table.concat, table.insert local statement_compilers = { raw = function(self, node) return self:add(node[2]) diff --git a/moonscript/compile/value.lua b/moonscript/compile/value.lua index f4352ea2..db3a2541 100644 --- a/moonscript/compile/value.lua +++ b/moonscript/compile/value.lua @@ -2,16 +2,21 @@ local util = require("moonscript.util") local data = require("moonscript.data") local ntype do - local _table_0 = require("moonscript.types") - ntype = _table_0.ntype + local _obj_0 = require("moonscript.types") + ntype = _obj_0.ntype end local user_error do - local _table_0 = require("moonscript.errors") - user_error = _table_0.user_error + local _obj_0 = require("moonscript.errors") + user_error = _obj_0.user_error end -local concat, insert = table.concat, table.insert -local unpack = util.unpack +local concat, insert +do + local _obj_0 = table + concat, insert = _obj_0.concat, _obj_0.insert +end +local unpack +unpack = util.unpack local table_delim = "," local string_chars = { ["\r"] = "\\r", diff --git a/moonscript/data.lua b/moonscript/data.lua index 83be3a88..69176969 100644 --- a/moonscript/data.lua +++ b/moonscript/data.lua @@ -1,4 +1,8 @@ -local concat, remove, insert = table.concat, table.remove, table.insert +local concat, remove, insert +do + local _obj_0 = table + concat, remove, insert = _obj_0.concat, _obj_0.remove, _obj_0.insert +end local Set Set = function(items) local self = { } diff --git a/moonscript/errors.lua b/moonscript/errors.lua index e36780cc..89f2520c 100644 --- a/moonscript/errors.lua +++ b/moonscript/errors.lua @@ -1,7 +1,12 @@ local util = require("moonscript.util") local lpeg = require("lpeg") -local concat, insert = table.concat, table.insert -local split, pos_to_line = util.split, util.pos_to_line +local concat, insert +do + local _obj_0 = table + concat, insert = _obj_0.concat, _obj_0.insert +end +local split, pos_to_line +split, pos_to_line = util.split, util.pos_to_line local user_error user_error = function(...) return error({ @@ -58,7 +63,8 @@ end local rewrite_traceback rewrite_traceback = function(text, err) local line_tables = require("moonscript.line_tables") - local V, S, Ct, C = lpeg.V, lpeg.S, lpeg.Ct, lpeg.C + local V, S, Ct, C + V, S, Ct, C = lpeg.V, lpeg.S, lpeg.Ct, lpeg.C local header_text = "stack traceback:" local Header, Line = V("Header"), V("Line") local Break = lpeg.S("\n") diff --git a/moonscript/init.lua b/moonscript/init.lua index 2488d6d9..1d31f800 100644 --- a/moonscript/init.lua +++ b/moonscript/init.lua @@ -1,10 +1,14 @@ local compile = require("moonscript.compile") local parse = require("moonscript.parse") -local concat, insert = table.concat, table.insert +local concat, insert +do + local _obj_0 = table + concat, insert = _obj_0.concat, _obj_0.insert +end local split, dump, get_options, unpack do - local _table_0 = require("moonscript.util") - split, dump, get_options, unpack = _table_0.split, _table_0.dump, _table_0.get_options, _table_0.unpack + local _obj_0 = require("moonscript.util") + split, dump, get_options, unpack = _obj_0.split, _obj_0.dump, _obj_0.get_options, _obj_0.unpack end local lua = { loadstring = loadstring, diff --git a/moonscript/transform.lua b/moonscript/transform.lua index caa773c9..f89e8c53 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -1,13 +1,19 @@ local types = require("moonscript.types") local util = require("moonscript.util") local data = require("moonscript.data") -local reversed, unpack = util.reversed, util.unpack -local ntype, mtype, build, smart_node, is_slice, value_is_singular = types.ntype, types.mtype, types.build, types.smart_node, types.is_slice, types.value_is_singular -local insert = table.insert +local reversed, unpack +reversed, unpack = util.reversed, util.unpack +local ntype, mtype, build, smart_node, is_slice, value_is_singular +ntype, mtype, build, smart_node, is_slice, value_is_singular = types.ntype, types.mtype, types.build, types.smart_node, types.is_slice, types.value_is_singular +local insert +do + local _obj_0 = table + insert = _obj_0.insert +end local NameProxy, LocalName do - local _table_0 = require("moonscript.transform.names") - NameProxy, LocalName = _table_0.NameProxy, _table_0.LocalName + local _obj_0 = require("moonscript.transform.names") + NameProxy, LocalName = _obj_0.NameProxy, _obj_0.LocalName end local destructure = require("moonscript.transform.destructure") local NOOP = { diff --git a/moonscript/transform/destructure.lua b/moonscript/transform/destructure.lua index 2cb88978..8659068f 100644 --- a/moonscript/transform/destructure.lua +++ b/moonscript/transform/destructure.lua @@ -1,23 +1,27 @@ local ntype, mtype, build do - local _table_0 = require("moonscript.types") - ntype, mtype, build = _table_0.ntype, _table_0.mtype, _table_0.build + local _obj_0 = require("moonscript.types") + ntype, mtype, build = _obj_0.ntype, _obj_0.mtype, _obj_0.build end local NameProxy do - local _table_0 = require("moonscript.transform.names") - NameProxy = _table_0.NameProxy + local _obj_0 = require("moonscript.transform.names") + NameProxy = _obj_0.NameProxy +end +local insert +do + local _obj_0 = table + insert = _obj_0.insert end -local insert = table.insert local unpack do - local _table_0 = require("moonscript.util") - unpack = _table_0.unpack + local _obj_0 = require("moonscript.util") + unpack = _obj_0.unpack end local user_error do - local _table_0 = require("moonscript.errors") - user_error = _table_0.user_error + local _obj_0 = require("moonscript.errors") + user_error = _obj_0.user_error end local util = require("moonscript.util") local join diff --git a/moonscript/transform/names.lua b/moonscript/transform/names.lua index 4d596bd3..c5596327 100644 --- a/moonscript/transform/names.lua +++ b/moonscript/transform/names.lua @@ -1,12 +1,12 @@ local build do - local _table_0 = require("moonscript.types") - build = _table_0.build + local _obj_0 = require("moonscript.types") + build = _obj_0.build end local unpack do - local _table_0 = require("moonscript.util") - unpack = _table_0.unpack + local _obj_0 = require("moonscript.util") + unpack = _obj_0.unpack end local LocalName do diff --git a/moonscript/types.lua b/moonscript/types.lua index a6d70fa6..b9087f6f 100644 --- a/moonscript/types.lua +++ b/moonscript/types.lua @@ -1,11 +1,16 @@ local util = require("moonscript.util") local Set do - local _table_0 = require("moonscript.data") - Set = _table_0.Set + local _obj_0 = require("moonscript.data") + Set = _obj_0.Set end -local insert = table.insert -local unpack = util.unpack +local insert +do + local _obj_0 = table + insert = _obj_0.insert +end +local unpack +unpack = util.unpack local manual_return = Set({ "foreach", "for", diff --git a/moonscript/util.lua b/moonscript/util.lua index d0e6bb09..78865c34 100644 --- a/moonscript/util.lua +++ b/moonscript/util.lua @@ -1,4 +1,8 @@ -local concat = table.concat +local concat +do + local _obj_0 = table + concat = _obj_0.concat +end local unpack = unpack or table.unpack local type = type local moon = { From 9dcb3ad1d187077f329d5853db6ebd53e7d794d4 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 29 Jun 2013 08:15:36 -0700 Subject: [PATCH 129/554] import spec --- spec/import_spec.moon | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 spec/import_spec.moon diff --git a/spec/import_spec.moon b/spec/import_spec.moon new file mode 100644 index 00000000..bb1472cd --- /dev/null +++ b/spec/import_spec.moon @@ -0,0 +1,26 @@ +describe "import", -> + it "should import from table", -> + import sort, insert from table + t = { 4,2,6 } + insert t, 1 + sort t + + assert.same t, {1,2,4,6} + + it "should import from local", -> + thing = { var: 10, hello: "world", func: => @var } + import hello, \func from thing + + assert.same hello, thing.hello + assert.same func!, thing.var + + it "should not call source multiple times", -> + count = 0 + source = -> + count += 1 + { hello: "world", foo: "bar" } + + import hello, foo from source! + + assert.same count, 1 + From 2d345f1c7c402165534a1c90ee467e5604376684 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 30 Jun 2013 20:13:12 -0700 Subject: [PATCH 130/554] change comprehensions again avoid problems overwritting values we are working with --- moonscript/transform.lua | 29 +++--- moonscript/transform.moon | 22 ++-- spec/comprehension_spec.moon | 6 ++ spec/outputs/bubbling.lua | 88 +++++++++------- spec/outputs/comprehension.lua | 104 ++++++++++++------- spec/outputs/lists.lua | 184 +++++++++++++++++++-------------- 6 files changed, 252 insertions(+), 181 deletions(-) diff --git a/moonscript/transform.lua b/moonscript/transform.lua index f89e8c53..cdfcbeb1 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -354,7 +354,7 @@ Statement = Transformer({ local _exp_0 = ntype(first_value) if "comprehension" == _exp_0 then local first_name = names[1] - local a = Accumulator(first_name) + local a = Accumulator() local action action = function(exp) return a:mutate_body({ @@ -362,7 +362,17 @@ Statement = Transformer({ }) end node = self.transform.statement(first_value, action, node) - return a:wrap(node, "group") + local wrapped = a:wrap(node, "do") + insert(wrapped[2], build.assign_one(first_name, a.accum_name)) + return build.group({ + { + "declare", + { + first_name + } + }, + wrapped + }) end end local transformed @@ -745,7 +755,7 @@ Statement = Transformer({ } } end - local out = build.group({ + return build.group({ list_name ~= list and build.assign_one(list_name, list) or NOOP, slice_var or NOOP, build["for"]({ @@ -763,8 +773,6 @@ Statement = Transformer({ } }) }) - out.has_unpack_copy = true - return out end node.body = with_continue_listener(node.body) end, @@ -1223,16 +1231,7 @@ do if group_type == nil then group_type = "block_exp" end - local copy_list - if rawget(node, "has_unpack_copy") then - do - local _with_0 = node[2][1] - node[2][1] = NOOP - copy_list = _with_0 - end - end return build[group_type]({ - copy_list or NOOP, build.assign_one(self.accum_name, build.table()), build.assign_one(self.len_name, 1), node, @@ -1279,7 +1278,7 @@ do _base_0.__index = _base_0 local _class_0 = setmetatable({ __init = function(self, accum_name) - self.accum_name = accum_name or NameProxy("accum") + self.accum_name = NameProxy("accum") self.value_name = NameProxy("value") self.len_name = NameProxy("len") end, diff --git a/moonscript/transform.moon b/moonscript/transform.moon index c6501b0d..e0b9f61d 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -180,11 +180,17 @@ Statement = Transformer { when "comprehension" first_name = names[1] - a = Accumulator first_name + a = Accumulator! action = (exp) -> a\mutate_body { exp } node = @transform.statement first_value, action, node - return a\wrap node, "group" + wrapped = a\wrap node, "do" + insert wrapped[2], build.assign_one first_name, a.accum_name + + return build.group { + {"declare", {first_name}} + wrapped + } -- bubble cascading assigns transformed = if num_values == 1 @@ -414,7 +420,7 @@ Statement = Transformer { else {1, {"length", list_name}} - out = build.group { + return build.group { list_name != list and build.assign_one(list_name, list) or NOOP slice_var or NOOP build["for"] { @@ -427,9 +433,6 @@ Statement = Transformer { } } - out.has_unpack_copy = true - return out - node.body = with_continue_listener node.body while: (node) => @@ -696,7 +699,7 @@ class Accumulator body_idx: { for: 4, while: 3, foreach: 4 } new: (accum_name) => - @accum_name = accum_name or NameProxy "accum" + @accum_name = NameProxy "accum" @value_name = NameProxy "value" @len_name = NameProxy "len" @@ -708,12 +711,7 @@ class Accumulator -- wrap the node into a block_exp wrap: (node, group_type="block_exp") => - copy_list = if rawget node, "has_unpack_copy" - with node[2][1] - node[2][1] = NOOP - build[group_type] { - copy_list or NOOP build.assign_one @accum_name, build.table! build.assign_one @len_name, 1 node diff --git a/spec/comprehension_spec.moon b/spec/comprehension_spec.moon index b7ac2270..86a5b9e2 100644 --- a/spec/comprehension_spec.moon +++ b/spec/comprehension_spec.moon @@ -35,6 +35,12 @@ describe "comprehension", -> assert.same input, {1,2,3,4} assert.same output, {2,4,6,8} + output = input + output = [i * 2 for _,i in ipairs input] + + assert.same input, {1,2,3,4} + assert.same output, {2,4,6,8} + it "should copy table", -> input = { 1,2,3, hello: "world", thing: true } diff --git a/spec/outputs/bubbling.lua b/spec/outputs/bubbling.lua index 38c0757b..db7ce949 100644 --- a/spec/outputs/bubbling.lua +++ b/spec/outputs/bubbling.lua @@ -18,38 +18,42 @@ dont_bubble = function() return _accum_0 end)() end -local k = { } -local _len_0 = 1 -for x in (function(...) - return print(...) -end)("hello") do - k[_len_0] = x - _len_0 = _len_0 + 1 +local k +do + local _accum_0 = { } + local _len_0 = 1 + for x in (function(...) + return print(...) + end)("hello") do + _accum_0[_len_0] = x + _len_0 = _len_0 + 1 + end + k = _accum_0 end local j = (function() local _accum_0 = { } - local _len_1 = 1 + local _len_0 = 1 for i = 1, 10 do - _accum_0[_len_1] = function(...) + _accum_0[_len_0] = function(...) return print(...) end - _len_1 = _len_1 + 1 + _len_0 = _len_0 + 1 end return _accum_0 end)() local m m = function(...) return (function(...) + local _accum_0 = { } + local _len_0 = 1 local _list_0 = { ... } - local _accum_0 = { } - local _len_1 = 1 for _index_0 = 1, #_list_0 do local x = _list_0[_index_0] if f(...) > 4 then - _accum_0[_len_1] = x - _len_1 = _len_1 + 1 + _accum_0[_len_0] = x + _len_0 = _len_0 + 1 end end return _accum_0 @@ -57,52 +61,60 @@ m = function(...) end local x = (function(...) local _accum_0 = { } - local _len_1 = 1 + local _len_0 = 1 local _list_0 = { ... } for _index_0 = 1, #_list_0 do local i = _list_0[_index_0] - _accum_0[_len_1] = i - _len_1 = _len_1 + 1 + _accum_0[_len_0] = i + _len_0 = _len_0 + 1 end return _accum_0 end)(...) -local _list_0 = { - ... -} -local y = { } -local _len_1 = 1 -for _index_0 = 1, #_list_0 do - x = _list_0[_index_0] - y[_len_1] = x - _len_1 = _len_1 + 1 +local y +do + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + x = _list_0[_index_0] + _accum_0[_len_0] = x + _len_0 = _len_0 + 1 + end + y = _accum_0 end -local z = { } -local _len_2 = 1 -for x in hallo do - if f(...) > 4 then - z[_len_2] = x - _len_2 = _len_2 + 1 +local z +do + local _accum_0 = { } + local _len_0 = 1 + for x in hallo do + if f(...) > 4 then + _accum_0[_len_0] = x + _len_0 = _len_0 + 1 + end end + z = _accum_0 end local a = (function(...) local _accum_0 = { } - local _len_3 = 1 + local _len_0 = 1 for i = 1, 10 do - _accum_0[_len_3] = ... - _len_3 = _len_3 + 1 + _accum_0[_len_0] = ... + _len_0 = _len_0 + 1 end return _accum_0 end)(...) local b = (function() local _accum_0 = { } - local _len_3 = 1 + local _len_0 = 1 for i = 1, 10 do - _accum_0[_len_3] = function() + _accum_0[_len_0] = function() return print(...) end - _len_3 = _len_3 + 1 + _len_0 = _len_0 + 1 end return _accum_0 end)() \ No newline at end of file diff --git a/spec/outputs/comprehension.lua b/spec/outputs/comprehension.lua index 7224b8ec..6b2f124d 100644 --- a/spec/outputs/comprehension.lua +++ b/spec/outputs/comprehension.lua @@ -79,60 +79,84 @@ _ = (function() end return _tbl_0 end)() -local n1 = { } -local _len_0 = 1 -for i = 1, 10 do - n1[_len_0] = i - _len_0 = _len_0 + 1 -end -local n2 = { } -local _len_1 = 1 -for i = 1, 10 do - if i % 2 == 1 then - n2[_len_1] = i - _len_1 = _len_1 + 1 +local n1 +do + local _accum_0 = { } + local _len_0 = 1 + for i = 1, 10 do + _accum_0[_len_0] = i + _len_0 = _len_0 + 1 end + n1 = _accum_0 end -local aa = { } -local _len_2 = 1 -for x = 1, 10 do - for y = 5, 14 do - aa[_len_2] = { - x, - y - } - _len_2 = _len_2 + 1 +local n2 +do + 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 + n2 = _accum_0 end -local bb = { } -local _len_3 = 1 -for thing in y do - for i = 1, 10 do - bb[_len_3] = y - _len_3 = _len_3 + 1 +local aa +do + 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 + aa = _accum_0 end -local cc = { } -local _len_4 = 1 -for i = 1, 10 do +local bb +do + local _accum_0 = { } + local _len_0 = 1 for thing in y do - cc[_len_4] = y - _len_4 = _len_4 + 1 + for i = 1, 10 do + _accum_0[_len_0] = y + _len_0 = _len_0 + 1 + end end + bb = _accum_0 end -local dd = { } -local _len_5 = 1 -for i = 1, 10 do - if cool then +local cc +do + local _accum_0 = { } + local _len_0 = 1 + for i = 1, 10 do for thing in y do - if x > 3 then - if c + 3 then - dd[_len_5] = y - _len_5 = _len_5 + 1 + _accum_0[_len_0] = y + _len_0 = _len_0 + 1 + end + end + cc = _accum_0 +end +local dd +do + 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 + dd = _accum_0 end _ = (function() local _tbl_0 = { } diff --git a/spec/outputs/lists.lua b/spec/outputs/lists.lua index 9566c908..2763314f 100644 --- a/spec/outputs/lists.lua +++ b/spec/outputs/lists.lua @@ -1,13 +1,17 @@ -local hi = { } -local _len_0 = 1 -for _, x in ipairs({ - 1, - 2, - 3, - 4 -}) do - hi[_len_0] = x * 2 - _len_0 = _len_0 + 1 +local hi +do + local _accum_0 = { } + local _len_0 = 1 + for _, x in ipairs({ + 1, + 2, + 3, + 4 + }) do + _accum_0[_len_0] = x * 2 + _len_0 = _len_0 + 1 + end + hi = _accum_0 end local items = { 1, @@ -17,33 +21,41 @@ local items = { 5, 6 } -local mm = { } -local _len_1 = 1 -for self.x in ipairs(items) do - mm[_len_1] = self.x - _len_1 = _len_1 + 1 +local mm +do + local _accum_0 = { } + local _len_0 = 1 + for self.x in ipairs(items) do + _accum_0[_len_0] = self.x + _len_0 = _len_0 + 1 + end + mm = _accum_0 end for z in ipairs(items) do if z > 4 then local _ = z end end -local rad = { } -local _len_2 = 1 -for a in ipairs({ - 1, - 2, - 3, - 4, - 5, - 6 -}) do - if good_number(a) then - rad[_len_2] = { - a - } - _len_2 = _len_2 + 1 +local rad +do + local _accum_0 = { } + local _len_0 = 1 + for a in ipairs({ + 1, + 2, + 3, + 4, + 5, + 6 + }) do + if good_number(a) then + _accum_0[_len_0] = { + a + } + _len_0 = _len_0 + 1 + end end + rad = _accum_0 end for z in items do for j in list do @@ -69,40 +81,44 @@ range = function(count) end dump((function() local _accum_0 = { } - local _len_3 = 1 + local _len_0 = 1 for x in range(10) do - _accum_0[_len_3] = x - _len_3 = _len_3 + 1 + _accum_0[_len_0] = x + _len_0 = _len_0 + 1 end return _accum_0 end)()) dump((function() local _accum_0 = { } - local _len_3 = 1 + local _len_0 = 1 for x in range(5) do if x > 2 then for y in range(5) do - _accum_0[_len_3] = { + _accum_0[_len_0] = { x, y } - _len_3 = _len_3 + 1 + _len_0 = _len_0 + 1 end end end return _accum_0 end)()) -local things = { } -local _len_3 = 1 -for x in range(10) do - if x > 5 then - for y in range(10) do - if y > 7 then - things[_len_3] = x + y - _len_3 = _len_3 + 1 +local things +do + local _accum_0 = { } + local _len_0 = 1 + for x in range(10) do + if x > 5 then + for y in range(10) do + if y > 7 then + _accum_0[_len_0] = x + y + _len_0 = _len_0 + 1 + end end end end + things = _accum_0 end for x in ipairs({ 1, @@ -125,11 +141,15 @@ end for x in x do local _ = x end -local x = { } -local _len_4 = 1 -for x in x do - x[_len_4] = x - _len_4 = _len_4 + 1 +local x +do + local _accum_0 = { } + local _len_0 = 1 + for x in x do + _accum_0[_len_0] = x + _len_0 = _len_0 + 1 + end + x = _accum_0 end for x in ipairs({ 1, @@ -146,35 +166,47 @@ for x in ipairs({ end end end -local double = { } -local _len_5 = 1 -for _index_0 = 1, #items do - x = items[_index_0] - double[_len_5] = x * 2 - _len_5 = _len_5 + 1 +local double +do + local _accum_0 = { } + local _len_0 = 1 + for _index_0 = 1, #items do + x = items[_index_0] + _accum_0[_len_0] = x * 2 + _len_0 = _len_0 + 1 + end + double = _accum_0 end for _index_0 = 1, #double do x = double[_index_0] print(x) end -local cut = { } -local _len_6 = 1 -for _index_0 = 1, #items do - x = items[_index_0] - if x > 3 then - cut[_len_6] = x - _len_6 = _len_6 + 1 +local cut +do + local _accum_0 = { } + local _len_0 = 1 + for _index_0 = 1, #items do + x = items[_index_0] + if x > 3 then + _accum_0[_len_0] = x + _len_0 = _len_0 + 1 + end end + cut = _accum_0 end -local hello = { } -local _len_7 = 1 -for _index_0 = 1, #items do - x = items[_index_0] - for _index_1 = 1, #items do - local y = items[_index_1] - hello[_len_7] = x + y - _len_7 = _len_7 + 1 +local hello +do + local _accum_0 = { } + local _len_0 = 1 + for _index_0 = 1, #items do + x = items[_index_0] + for _index_1 = 1, #items do + local y = items[_index_1] + _accum_0[_len_0] = x + y + _len_0 = _len_0 + 1 + end end + hello = _accum_0 end for _index_0 = 1, #hello do local z = hello[_index_0] @@ -227,10 +259,10 @@ local normal normal = function(hello) return (function() local _accum_0 = { } - local _len_8 = 1 + local _len_0 = 1 for x in yeah do - _accum_0[_len_8] = x - _len_8 = _len_8 + 1 + _accum_0[_len_0] = x + _len_0 = _len_0 + 1 end return _accum_0 end)() @@ -257,11 +289,11 @@ end return function() return (function() local _accum_0 = { } - local _len_8 = 1 + local _len_0 = 1 for _index_0 = 1, #things do x = things[_index_0] - _accum_0[_len_8] = x - _len_8 = _len_8 + 1 + _accum_0[_len_0] = x + _len_0 = _len_0 + 1 end return _accum_0 end)() From 931596d6af15a1a6e9013d601fd464696f63f9b4 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 30 Jun 2013 20:32:59 -0700 Subject: [PATCH 131/554] handle general case of block_exp single assign --- moonscript/transform.lua | 33 ++++++++++++++++++++------------- moonscript/transform.moon | 24 +++++++++++++++--------- 2 files changed, 35 insertions(+), 22 deletions(-) diff --git a/moonscript/transform.lua b/moonscript/transform.lua index cdfcbeb1..4cdf5977 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -351,19 +351,12 @@ Statement = Transformer({ local num_names = #values if num_names == 1 and num_values == 1 then local first_value = values[1] + local first_name = names[1] local _exp_0 = ntype(first_value) - if "comprehension" == _exp_0 then - local first_name = names[1] - local a = Accumulator() - local action - action = function(exp) - return a:mutate_body({ - exp - }) - end - node = self.transform.statement(first_value, action, node) - local wrapped = a:wrap(node, "do") - insert(wrapped[2], build.assign_one(first_name, a.accum_name)) + if "block_exp" == _exp_0 then + local block_body = first_value[2] + local idx = #block_body + block_body[idx] = build.assign_one(first_name, block_body[idx]) return build.group({ { "declare", @@ -371,8 +364,22 @@ Statement = Transformer({ first_name } }, - wrapped + { + "do", + block_body + } }) + elseif "comprehension" == _exp_0 then + local a = Accumulator() + local action + action = function(exp) + return a:mutate_body({ + exp + }) + end + node = self.transform.statement(first_value, action, node) + local wrapped = a:wrap(node) + return build.assign_one(first_name, wrapped) end end local transformed diff --git a/moonscript/transform.moon b/moonscript/transform.moon index e0b9f61d..8a448014 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -174,23 +174,29 @@ Statement = Transformer { num_values = #values num_names = #values + -- special code simplifications for single assigns if num_names == 1 and num_values == 1 first_value = values[1] + first_name = names[1] + switch ntype first_value - when "comprehension" - first_name = names[1] + when "block_exp" + block_body = first_value[2] + idx = #block_body + block_body[idx] = build.assign_one first_name, block_body[idx] + + return build.group { + {"declare", {first_name}} + {"do", block_body} + } + when "comprehension" a = Accumulator! action = (exp) -> a\mutate_body { exp } node = @transform.statement first_value, action, node - wrapped = a\wrap node, "do" - insert wrapped[2], build.assign_one first_name, a.accum_name - - return build.group { - {"declare", {first_name}} - wrapped - } + wrapped = a\wrap node + return build.assign_one first_name, wrapped -- bubble cascading assigns transformed = if num_values == 1 From dcf95321c0725d0fe09df42188c1fb66484abb59 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 30 Jun 2013 20:44:06 -0700 Subject: [PATCH 132/554] remove/rearrange misc --- moonscript/transform.lua | 11 +++-------- moonscript/transform.moon | 9 +++------ moonscript/types.moon | 2 ++ 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 4cdf5977..6d6eac47 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -378,8 +378,7 @@ Statement = Transformer({ }) end node = self.transform.statement(first_value, action, node) - local wrapped = a:wrap(node) - return build.assign_one(first_name, wrapped) + return build.assign_one(first_name, a:wrap(node)) end end local transformed @@ -689,7 +688,7 @@ Statement = Transformer({ end)() }) end, - foreach = function(self, node, _, parent_assign) + foreach = function(self, node, _) smart_node(node) local source = unpack(node.iter) local destructures = { } @@ -717,11 +716,7 @@ Statement = Transformer({ if ntype(source) == "unpack" then local list = source[2] local index_name = NameProxy("index") - local assign_name - if parent_assign then - assign_name = parent_assign[2][1] - end - local list_name = assign_name ~= list and self:is_local(list) and list or NameProxy("list") + local list_name = self:is_local(list) and list or NameProxy("list") local slice_var = nil local bounds if is_slice(list) then diff --git a/moonscript/transform.moon b/moonscript/transform.moon index 8a448014..2f871612 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -194,9 +194,7 @@ Statement = Transformer { a = Accumulator! action = (exp) -> a\mutate_body { exp } node = @transform.statement first_value, action, node - - wrapped = a\wrap node - return build.assign_one first_name, wrapped + return build.assign_one first_name, a\wrap node -- bubble cascading assigns transformed = if num_values == 1 @@ -384,7 +382,7 @@ Statement = Transformer { ret scope_name } - foreach: (node, _, parent_assign) => + foreach: (node, _) => smart_node node source = unpack node.iter @@ -404,8 +402,7 @@ Statement = Transformer { list = source[2] index_name = NameProxy "index" - assign_name = parent_assign[2][1] if parent_assign - list_name = assign_name != list and @is_local(list) and list or NameProxy "list" + list_name = @is_local(list) and list or NameProxy "list" slice_var = nil bounds = if is_slice list diff --git a/moonscript/types.moon b/moonscript/types.moon index e603f602..aee741ad 100644 --- a/moonscript/types.moon +++ b/moonscript/types.moon @@ -122,8 +122,10 @@ build = nil build = setmetatable { group: (body={}) -> {"group", body} + do: (body) -> {"do", body} + assign_one: (name, value) -> build.assign { names: {name} From 77358045088acdc88aab8a02b1bfb9f4b8bc4663 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 30 Jun 2013 21:05:52 -0700 Subject: [PATCH 133/554] more comprehension specs --- spec/comprehension_spec.moon | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/spec/comprehension_spec.moon b/spec/comprehension_spec.moon index 86a5b9e2..2f07939d 100644 --- a/spec/comprehension_spec.moon +++ b/spec/comprehension_spec.moon @@ -42,9 +42,34 @@ describe "comprehension", -> assert.same output, {2,4,6,8} +describe "table comprehension", -> it "should copy table", -> input = { 1,2,3, hello: "world", thing: true } output = {k,v for k,v in pairs input } assert.is_true input != output assert.same input, output + + it "should support when", -> + input = { + color: "red" + name: "fast" + width: 123 + } + + output = { k,v for k,v in pairs input when k != "color" } + + assert.same output, { name: "fast", width: 123 } + + it "should do unpack", -> + input = {4,9,16,25} + output = {i, math.sqrt i for i in *input} + + assert.same output, { [4]: 2, [9]: 3, [16]: 4, [25]: 5 } + + it "should use multiple return values", -> + input = { {"hello", "world"}, {"foo", "bar"} } + output = { unpack tuple for tuple in *input } + + assert.same output, { foo: "bar", hello: "world" } + From 82f73842d800877d29d710dd664d310090b89085 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 30 Jun 2013 21:06:31 -0700 Subject: [PATCH 134/554] don't create unecessary function with tblcomp and assign single --- moonscript/transform.lua | 12 ++------- moonscript/transform.moon | 8 +++--- spec/outputs/comprehension.lua | 45 ++++++++++++++++++---------------- 3 files changed, 29 insertions(+), 36 deletions(-) diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 6d6eac47..aec42962 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -369,16 +369,8 @@ Statement = Transformer({ block_body } }) - elseif "comprehension" == _exp_0 then - local a = Accumulator() - local action - action = function(exp) - return a:mutate_body({ - exp - }) - end - node = self.transform.statement(first_value, action, node) - return build.assign_one(first_name, a:wrap(node)) + elseif "comprehension" == _exp_0 or "tblcomprehension" == _exp_0 then + return build.assign_one(first_name, Value.transformers[first_value[1]](self, first_value)) end end local transformed diff --git a/moonscript/transform.moon b/moonscript/transform.moon index 2f871612..53d62878 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -190,11 +190,9 @@ Statement = Transformer { {"do", block_body} } - when "comprehension" - a = Accumulator! - action = (exp) -> a\mutate_body { exp } - node = @transform.statement first_value, action, node - return build.assign_one first_name, a\wrap node + when "comprehension", "tblcomprehension" + return build.assign_one first_name, + Value.transformers[first_value[1]] @, first_value -- bubble cascading assigns transformed = if num_values == 1 diff --git a/spec/outputs/comprehension.lua b/spec/outputs/comprehension.lua index 6b2f124d..7512c5f3 100644 --- a/spec/outputs/comprehension.lua +++ b/spec/outputs/comprehension.lua @@ -6,35 +6,38 @@ local items = { 5, 6 } -local out = (function() +local out +do local _tbl_0 = { } for k in items do _tbl_0[k] = k * 2 end - return _tbl_0 -end)() + out = _tbl_0 +end local x = { hello = "world", okay = 2323 } -local copy = (function() +local copy +do local _tbl_0 = { } for k, v in pairs(x) do if k ~= "okay" then _tbl_0[k] = v end end - return _tbl_0 -end)() -local _ = (function() + copy = _tbl_0 +end +local _ +do local _tbl_0 = { } for x in yes do local _key_0, _val_0 = unpack(x) _tbl_0[_key_0] = _val_0 end - return _tbl_0 -end)() -_ = (function() + _ = _tbl_0 +end +do local _tbl_0 = { } local _list_0 = yes for _index_0 = 1, #_list_0 do @@ -42,17 +45,17 @@ _ = (function() local _key_0, _val_0 = unpack(x) _tbl_0[_key_0] = _val_0 end - return _tbl_0 -end)() -_ = (function() + _ = _tbl_0 +end +do local _tbl_0 = { } for x in yes do local _key_0, _val_0 = xxxx _tbl_0[_key_0] = _val_0 end - return _tbl_0 -end)() -_ = (function() + _ = _tbl_0 +end +do local _tbl_0 = { } local _list_0 = { { @@ -77,8 +80,8 @@ _ = (function() end)()) _tbl_0[_key_0] = _val_0 end - return _tbl_0 -end)() + _ = _tbl_0 +end local n1 do local _accum_0 = { } @@ -158,11 +161,11 @@ do end dd = _accum_0 end -_ = (function() +do local _tbl_0 = { } for i = 1, 10 do _tbl_0["hello"] = "world" end - return _tbl_0 -end)() + _ = _tbl_0 +end return nil \ No newline at end of file From 642932c1d557e0bc7b189f808fc7ada1e8c65f0f Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 30 Jun 2013 21:20:01 -0700 Subject: [PATCH 135/554] kill some more anon funcs for while,for,foreach --- moonscript/transform.lua | 2 +- moonscript/transform.moon | 2 +- spec/outputs/bubbling.lua | 28 +++++++++++++----------- spec/outputs/loops.lua | 45 +++++++++++++++++++++------------------ 4 files changed, 42 insertions(+), 35 deletions(-) diff --git a/moonscript/transform.lua b/moonscript/transform.lua index aec42962..471132fc 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -369,7 +369,7 @@ Statement = Transformer({ block_body } }) - elseif "comprehension" == _exp_0 or "tblcomprehension" == _exp_0 then + elseif "comprehension" == _exp_0 or "tblcomprehension" == _exp_0 or "foreach" == _exp_0 or "for" == _exp_0 or "while" == _exp_0 then return build.assign_one(first_name, Value.transformers[first_value[1]](self, first_value)) end end diff --git a/moonscript/transform.moon b/moonscript/transform.moon index 53d62878..a3b3f6ee 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -190,7 +190,7 @@ Statement = Transformer { {"do", block_body} } - when "comprehension", "tblcomprehension" + when "comprehension", "tblcomprehension", "foreach", "for", "while" return build.assign_one first_name, Value.transformers[first_value[1]] @, first_value diff --git a/spec/outputs/bubbling.lua b/spec/outputs/bubbling.lua index db7ce949..c0bc5fe7 100644 --- a/spec/outputs/bubbling.lua +++ b/spec/outputs/bubbling.lua @@ -30,7 +30,8 @@ do end k = _accum_0 end -local j = (function() +local j +do local _accum_0 = { } local _len_0 = 1 for i = 1, 10 do @@ -39,8 +40,8 @@ local j = (function() end _len_0 = _len_0 + 1 end - return _accum_0 -end)() + j = _accum_0 +end local m m = function(...) return (function(...) @@ -59,7 +60,8 @@ m = function(...) return _accum_0 end)(...) end -local x = (function(...) +local x +do local _accum_0 = { } local _len_0 = 1 local _list_0 = { @@ -70,8 +72,8 @@ local x = (function(...) _accum_0[_len_0] = i _len_0 = _len_0 + 1 end - return _accum_0 -end)(...) + x = _accum_0 +end local y do local _accum_0 = { } @@ -98,16 +100,18 @@ do end z = _accum_0 end -local a = (function(...) +local a +do local _accum_0 = { } local _len_0 = 1 for i = 1, 10 do _accum_0[_len_0] = ... _len_0 = _len_0 + 1 end - return _accum_0 -end)(...) -local b = (function() + a = _accum_0 +end +local b +do local _accum_0 = { } local _len_0 = 1 for i = 1, 10 do @@ -116,5 +120,5 @@ local b = (function() end _len_0 = _len_0 + 1 end - return _accum_0 -end)() \ No newline at end of file + b = _accum_0 +end \ No newline at end of file diff --git a/spec/outputs/loops.lua b/spec/outputs/loops.lua index 47df0d7c..dcba0bc1 100644 --- a/spec/outputs/loops.lua +++ b/spec/outputs/loops.lua @@ -48,7 +48,7 @@ local hello = { 4, 5 } -x = (function() +do local _accum_0 = { } local _len_0 = 1 for _index_0 = 1, #hello do @@ -58,25 +58,27 @@ x = (function() end _len_0 = _len_0 + 1 end - return _accum_0 -end)() + x = _accum_0 +end x = function() for _index_0 = 1, #hello do x = hello[_index_0] local _ = y end end -local t = (function() +local t +do local _accum_0 = { } local _len_0 = 1 for i = 10, 20 do _accum_0[_len_0] = i * 2 _len_0 = _len_0 + 1 end - return _accum_0 -end)() + t = _accum_0 +end local hmm = 0 -local y = (function() +local y +do local _accum_0 = { } local _len_0 = 1 for j = 3, 30, 8 do @@ -85,8 +87,8 @@ local y = (function() _accum_0[_len_0] = _value_0 _len_0 = _len_0 + 1 end - return _accum_0 -end)() + y = _accum_0 +end local _ _ = function() for k = 10, 40 do @@ -116,7 +118,7 @@ while also do _ = "okay" end local i = 0 -x = (function() +do local _accum_0 = { } local _len_0 = 1 while i < 10 do @@ -125,9 +127,9 @@ x = (function() _accum_0[_len_0] = _value_0 _len_0 = _len_0 + 1 end - return _accum_0 -end)() -x = (function() + x = _accum_0 +end +do local _accum_0 = { } local _len_0 = 1 local _list_1 = 3 @@ -138,9 +140,9 @@ x = (function() _accum_0[_len_0] = _value_0 _len_0 = _len_0 + 1 end - return _accum_0 -end)() -x = (function() + x = _accum_0 +end +do local _accum_0 = { } local _len_0 = 1 for x = 1, 2 do @@ -149,8 +151,8 @@ x = (function() _accum_0[_len_0] = _value_0 _len_0 = _len_0 + 1 end - return _accum_0 -end)() + x = _accum_0 +end while true do local _continue_0 = false repeat @@ -183,7 +185,8 @@ for x = 1, 10 do break end end -local list = (function() +local list +do local _accum_0 = { } local _len_0 = 1 for x = 1, 10 do @@ -202,8 +205,8 @@ local list = (function() break end end - return _accum_0 -end)() + list = _accum_0 +end local _list_1 = { 1, 2, From 0848c1ea715f02de7c64725bebab038ba0470fb4 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 30 Jun 2013 21:33:41 -0700 Subject: [PATCH 136/554] rebuild this sucker :triumph: --- moonscript/compile.lua | 7 +++-- moonscript/compile/value.lua | 40 +++++++++++++++---------- moonscript/dump.lua | 16 ++++++---- moonscript/errors.lua | 19 +++++++----- moonscript/transform.lua | 45 +++++++++++++++------------- moonscript/transform/destructure.lua | 12 ++++---- moonscript/transform/names.lua | 7 +++-- moonscript/util.lua | 40 ++++++++++++++----------- 8 files changed, 107 insertions(+), 79 deletions(-) diff --git a/moonscript/compile.lua b/moonscript/compile.lua index 561e822f..a3f61acb 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -306,7 +306,8 @@ do end end, declare = function(self, names) - local undeclared = (function() + local undeclared + do local _accum_0 = { } local _len_0 = 1 for _index_0 = 1, #names do @@ -342,8 +343,8 @@ do break end end - return _accum_0 - end)() + undeclared = _accum_0 + end return undeclared end, whitelist_names = function(self, names) diff --git a/moonscript/compile/value.lua b/moonscript/compile/value.lua index db3a2541..b4d6e3a3 100644 --- a/moonscript/compile/value.lua +++ b/moonscript/compile/value.lua @@ -51,9 +51,9 @@ local value_compilers = { do local _with_0 = self:line() _with_0:append_list((function() - local _list_0 = node local _accum_0 = { } local _len_0 = 1 + local _list_0 = node for _index_0 = 2, #_list_0 do local v = _list_0[_index_0] _accum_0[_len_0] = self:value(v) @@ -128,7 +128,8 @@ local value_compilers = { local _, args, whitelist, arrow, block = unpack(node) local default_args = { } local self_args = { } - local arg_names = (function() + local arg_names + do local _accum_0 = { } local _len_0 = 1 for _index_0 = 1, #args do @@ -149,8 +150,8 @@ local value_compilers = { _accum_0[_len_0] = _value_0 _len_0 = _len_0 + 1 end - return _accum_0 - end)() + arg_names = _accum_0 + end if arrow == "fat" then insert(arg_names, 1, "self") end @@ -190,12 +191,16 @@ local value_compilers = { } }) end - local self_arg_values = { } - local _len_0 = 1 - for _index_0 = 1, #self_args do - local arg = self_args[_index_0] - self_arg_values[_len_0] = arg[2] - _len_0 = _len_0 + 1 + local self_arg_values + do + local _accum_0 = { } + local _len_0 = 1 + for _index_0 = 1, #self_args do + local arg = self_args[_index_0] + _accum_0[_len_0] = arg[2] + _len_0 = _len_0 + 1 + end + self_arg_values = _accum_0 end if #self_args > 0 then _with_0:stm({ @@ -206,12 +211,15 @@ local value_compilers = { end _with_0:stms(block) if #args > #arg_names then - arg_names = { } - local _len_1 = 1 - for _index_0 = 1, #args do - local arg = args[_index_0] - arg_names[_len_1] = arg[1] - _len_1 = _len_1 + 1 + do + local _accum_0 = { } + local _len_0 = 1 + for _index_0 = 1, #args do + local arg = args[_index_0] + _accum_0[_len_0] = arg[1] + _len_0 = _len_0 + 1 + end + arg_names = _accum_0 end end _with_0.header = "function(" .. concat(arg_names, ", ") .. ")" diff --git a/moonscript/dump.lua b/moonscript/dump.lua index 3536babb..8b69ec93 100644 --- a/moonscript/dump.lua +++ b/moonscript/dump.lua @@ -9,12 +9,16 @@ flat_value = function(op, depth) if type(op) ~= "table" then return tostring(op) end - local items = { } - local _len_0 = 1 - for _index_0 = 1, #op do - local item = op[_index_0] - items[_len_0] = flat_value(item, depth + 1) - _len_0 = _len_0 + 1 + local items + do + local _accum_0 = { } + local _len_0 = 1 + for _index_0 = 1, #op do + local item = op[_index_0] + _accum_0[_len_0] = flat_value(item, depth + 1) + _len_0 = _len_0 + 1 + end + items = _accum_0 end local pos = op[-1] return "{" .. (pos and "[" .. pos .. "] " or "") .. table.concat(items, ", ") .. "}" diff --git a/moonscript/errors.lua b/moonscript/errors.lua index 89f2520c..91a91a10 100644 --- a/moonscript/errors.lua +++ b/moonscript/errors.lua @@ -47,14 +47,17 @@ truncate_traceback = function(traceback, chunk_func) end stop = stop - 1 end - local _list_0 = traceback - traceback = { } - local _len_0 = 1 - local _max_0 = stop - for _index_0 = 1, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do - local t = _list_0[_index_0] - traceback[_len_0] = t - _len_0 = _len_0 + 1 + do + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = traceback + local _max_0 = stop + for _index_0 = 1, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do + local t = _list_0[_index_0] + _accum_0[_len_0] = t + _len_0 = _len_0 + 1 + end + traceback = _accum_0 end local rep = "function '" .. chunk_func .. "'" traceback[#traceback] = traceback[#traceback]:gsub(rep, "main chunk") diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 471132fc..5ec0ab7e 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -317,7 +317,7 @@ Statement = Transformer({ declare_glob = function(self, node) local names = extract_declarations(self) if node[2] == "^" then - names = (function() + do local _accum_0 = { } local _len_0 = 1 for _index_0 = 1, #names do @@ -337,8 +337,8 @@ Statement = Transformer({ break end end - return _accum_0 - end)() + names = _accum_0 + end end return { "declare", @@ -470,7 +470,8 @@ Statement = Transformer({ end, import = function(self, node) local _, names, source = unpack(node) - local table_values = (function() + local table_values + do local _accum_0 = { } local _len_0 = 1 for _index_0 = 1, #names do @@ -491,8 +492,8 @@ Statement = Transformer({ _accum_0[_len_0] = _value_0 _len_0 = _len_0 + 1 end - return _accum_0 - end)() + table_values = _accum_0 + end local dest = { "table", table_values @@ -566,9 +567,9 @@ Statement = Transformer({ wrapped = build.group({ build.declare({ names = (function() - local _list_0 = stm[2] local _accum_0 = { } local _len_0 = 1 + local _list_0 = stm[2] for _index_0 = 1, #_list_0 do local name = _list_0[_index_0] if type(name) == "string" then @@ -684,7 +685,7 @@ Statement = Transformer({ smart_node(node) local source = unpack(node.iter) local destructures = { } - node.names = (function() + do local _accum_0 = { } local _len_0 = 1 for i, name in ipairs(node.names) do @@ -699,8 +700,8 @@ Statement = Transformer({ end _len_0 = _len_0 + 1 end - return _accum_0 - end)() + node.names = _accum_0 + end if next(destructures) then insert(destructures, build.group(node.body)) node.body = destructures @@ -862,7 +863,7 @@ Statement = Transformer({ end end local constructor - properties = (function() + do local _accum_0 = { } local _len_0 = 1 for _index_0 = 1, #properties do @@ -886,8 +887,8 @@ Statement = Transformer({ break end end - return _accum_0 - end)() + properties = _accum_0 + end local parent_cls_name = NameProxy("parent") local base_name = NameProxy("base") local self_name = NameProxy("self") @@ -1066,13 +1067,17 @@ Statement = Transformer({ end return self:set("super", function(block, chain) if chain then - local _list_0 = chain - local slice = { } - local _len_0 = 1 - for _index_0 = 3, #_list_0 do - local item = _list_0[_index_0] - slice[_len_0] = item - _len_0 = _len_0 + 1 + local slice + do + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = chain + for _index_0 = 3, #_list_0 do + local item = _list_0[_index_0] + _accum_0[_len_0] = item + _len_0 = _len_0 + 1 + end + slice = _accum_0 end local new_chain = { "chain", diff --git a/moonscript/transform/destructure.lua b/moonscript/transform/destructure.lua index 8659068f..dcfa3970 100644 --- a/moonscript/transform/destructure.lua +++ b/moonscript/transform/destructure.lua @@ -198,15 +198,15 @@ split_assign = function(scope, assign) "_" } else - name_slice = (function() + do local _accum_0 = { } local _len_0 = 1 for i = start, total_names do _accum_0[_len_0] = names[i] _len_0 = _len_0 + 1 end - return _accum_0 - end)() + name_slice = _accum_0 + end end local value_slice if total_values < start then @@ -214,15 +214,15 @@ split_assign = function(scope, assign) "nil" } else - value_slice = (function() + do local _accum_0 = { } local _len_0 = 1 for i = start, total_values do _accum_0[_len_0] = values[i] _len_0 = _len_0 + 1 end - return _accum_0 - end)() + value_slice = _accum_0 + end end insert(g, { "assign", diff --git a/moonscript/transform/names.lua b/moonscript/transform/names.lua index c5596327..987d71cd 100644 --- a/moonscript/transform/names.lua +++ b/moonscript/transform/names.lua @@ -47,7 +47,8 @@ do return self.name end, chain = function(self, ...) - local items = (function(...) + local items + do local _accum_0 = { } local _len_0 = 1 local _list_0 = { @@ -65,8 +66,8 @@ do end _len_0 = _len_0 + 1 end - return _accum_0 - end)(...) + items = _accum_0 + end return build.chain({ base = self, unpack(items) diff --git a/moonscript/util.lua b/moonscript/util.lua index 78865c34..7e5631dc 100644 --- a/moonscript/util.lua +++ b/moonscript/util.lua @@ -104,15 +104,16 @@ dump = function(what) end seen[what] = true depth = depth + 1 - local lines = (function() + local lines + do local _accum_0 = { } local _len_0 = 1 for k, v in pairs(what) do _accum_0[_len_0] = (" "):rep(depth * 4) .. "[" .. tostring(k) .. "] = " .. _dump(v, depth) _len_0 = _len_0 + 1 end - return _accum_0 - end)() + lines = _accum_0 + end seen[what] = false return "{\n" .. concat(lines) .. (" "):rep((depth - 1) * 4) .. "}\n" else @@ -123,21 +124,26 @@ dump = function(what) end local debug_posmap debug_posmap = function(posmap, moon_code, lua_code) - local tuples = { } - local _len_0 = 1 - for k, v in pairs(posmap) do - tuples[_len_0] = { - k, - v - } - _len_0 = _len_0 + 1 + local tuples + do + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(posmap) do + _accum_0[_len_0] = { + k, + v + } + _len_0 = _len_0 + 1 + end + tuples = _accum_0 end table.sort(tuples, function(a, b) return a[1] < b[1] end) - local lines = (function() + local lines + do local _accum_0 = { } - local _len_1 = 1 + local _len_0 = 1 for _index_0 = 1, #tuples do local pair = tuples[_index_0] local lua_line, pos = unpack(pair) @@ -145,11 +151,11 @@ debug_posmap = function(posmap, moon_code, lua_code) local lua_text = get_line(lua_code, lua_line) local moon_text = get_closest_line(moon_code, moon_line) local _value_0 = tostring(pos) .. "\t " .. tostring(lua_line) .. ":[ " .. tostring(trim(lua_text)) .. " ] >> " .. tostring(moon_line) .. ":[ " .. tostring(trim(moon_text)) .. " ]" - _accum_0[_len_1] = _value_0 - _len_1 = _len_1 + 1 + _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 end - return _accum_0 - end)() + lines = _accum_0 + end return concat(lines, "\n") end local setfenv = setfenv or function(fn, env) From f04af88a8df1293d4c8581b5822ec481febba46f Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 30 Jun 2013 21:40:10 -0700 Subject: [PATCH 137/554] slices will reuse local vars for list --- moonscript/compile.lua | 3 +++ moonscript/compile.moon | 4 ++++ moonscript/transform.lua | 3 +++ moonscript/transform.moon | 3 +++ spec/outputs/lists.lua | 36 +++++++++++++++--------------------- 5 files changed, 28 insertions(+), 21 deletions(-) diff --git a/moonscript/compile.lua b/moonscript/compile.lua index a3f61acb..5892c20d 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -389,6 +389,9 @@ do if t == NameProxy or t == LocalName then return true end + if t == "table" and node[1] == "chain" and #node == 2 then + return self:is_local(node[2]) + end return false end, free_name = function(self, prefix, dont_put) diff --git a/moonscript/compile.moon b/moonscript/compile.moon index d1f0315d..0d999460 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -257,6 +257,10 @@ class Block t = mtype node return @has_name(node, false) if t == "string" return true if t == NameProxy or t == LocalName + + if t == "table" and node[1] == "chain" and #node == 2 + return @is_local node[2] + false free_name: (prefix, dont_put) => diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 5ec0ab7e..f1e16de8 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -716,6 +716,9 @@ Statement = Transformer({ local slice = list[#list] table.remove(list) table.remove(slice, 1) + if self:is_local(list) then + list_name = list + end if slice[2] and slice[2] ~= "" then local max_tmp_name = NameProxy("max") slice_var = build.assign_one(max_tmp_name, slice[2]) diff --git a/moonscript/transform.moon b/moonscript/transform.moon index a3b3f6ee..06671979 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -400,6 +400,7 @@ Statement = Transformer { list = source[2] index_name = NameProxy "index" + list_name = @is_local(list) and list or NameProxy "list" slice_var = nil @@ -408,6 +409,8 @@ Statement = Transformer { table.remove list table.remove slice, 1 + list_name = list if @is_local list + slice[2] = if slice[2] and slice[2] != "" max_tmp_name = NameProxy "max" slice_var = build.assign_one max_tmp_name, slice[2] diff --git a/spec/outputs/lists.lua b/spec/outputs/lists.lua index 2763314f..7428af49 100644 --- a/spec/outputs/lists.lua +++ b/spec/outputs/lists.lua @@ -221,38 +221,32 @@ x = { 6, 7 } -local _list_0 = x local _max_0 = -5 -for _index_0 = 2, _max_0 < 0 and #_list_0 + _max_0 or _max_0, 2 do - local y = _list_0[_index_0] +for _index_0 = 2, _max_0 < 0 and #x + _max_0 or _max_0, 2 do + local y = x[_index_0] print(y) end -local _list_1 = x local _max_1 = 3 -for _index_0 = 1, _max_1 < 0 and #_list_1 + _max_1 or _max_1 do - local y = _list_1[_index_0] +for _index_0 = 1, _max_1 < 0 and #x + _max_1 or _max_1 do + local y = x[_index_0] print(y) end -local _list_2 = x -for _index_0 = 2, #_list_2 do - local y = _list_2[_index_0] +for _index_0 = 2, #x do + local y = x[_index_0] print(y) end -local _list_3 = x -for _index_0 = 1, #_list_3, 2 do - local y = _list_3[_index_0] +for _index_0 = 1, #x, 2 do + local y = x[_index_0] print(y) end -local _list_4 = x -for _index_0 = 2, #_list_4, 2 do - local y = _list_4[_index_0] +for _index_0 = 2, #x, 2 do + local y = x[_index_0] print(y) end local a, b, c = 1, 5, 2 -local _list_5 = x local _max_2 = b -for _index_0 = a, _max_2 < 0 and #_list_5 + _max_2 or _max_2, c do - local y = _list_5[_index_0] +for _index_0 = a, _max_2 < 0 and #x + _max_2 or _max_2, c do + local y = x[_index_0] print(y) end local normal @@ -274,9 +268,9 @@ for _index_0 = 1, #test do end local _ _ = function() - local _list_6 = rows - for _index_0 = 1, #_list_6 do - local row = _list_6[_index_0] + local _list_0 = rows + for _index_0 = 1, #_list_0 do + local row = _list_0[_index_0] a = b end end From bc2dee76b5a54851bb95ad117046de3d0fc8f89e Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 30 Jun 2013 21:47:45 -0700 Subject: [PATCH 138/554] continue spec --- spec/loops_spec.moon | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 spec/loops_spec.moon diff --git a/spec/loops_spec.moon b/spec/loops_spec.moon new file mode 100644 index 00000000..68b5f97f --- /dev/null +++ b/spec/loops_spec.moon @@ -0,0 +1,9 @@ + +describe "loops", -> + it "should continue", -> + input = {1,2,3,4,5,6} + output = for x in *input + continue if x % 2 == 1 + x + + assert.same output, { 2,4,6 } From 7085304207aa197f4b4c0e03b4e0c4e51dd3bc21 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 30 Jun 2013 21:47:56 -0700 Subject: [PATCH 139/554] rebuild --- moonscript/compile/statement.lua | 5 ++--- moonscript/compile/value.lua | 10 ++++------ moonscript/errors.lua | 5 ++--- moonscript/transform.lua | 10 ++++------ 4 files changed, 12 insertions(+), 18 deletions(-) diff --git a/moonscript/compile/statement.lua b/moonscript/compile/statement.lua index bf858070..65cc2d5e 100644 --- a/moonscript/compile/statement.lua +++ b/moonscript/compile/statement.lua @@ -140,9 +140,8 @@ local statement_compilers = { current.next = next current = next end - local _list_0 = node - for _index_0 = 4, #_list_0 do - cond = _list_0[_index_0] + for _index_0 = 4, #node do + cond = node[_index_0] add_clause(cond) end return root diff --git a/moonscript/compile/value.lua b/moonscript/compile/value.lua index b4d6e3a3..d5494ea5 100644 --- a/moonscript/compile/value.lua +++ b/moonscript/compile/value.lua @@ -53,9 +53,8 @@ local value_compilers = { _with_0:append_list((function() local _accum_0 = { } local _len_0 = 1 - local _list_0 = node - for _index_0 = 2, #_list_0 do - local v = _list_0[_index_0] + for _index_0 = 2, #node do + local v = node[_index_0] _accum_0[_len_0] = self:value(v) _len_0 = _len_0 + 1 end @@ -115,9 +114,8 @@ local value_compilers = { local actions do local _with_0 = self:line() - local _list_0 = node - for _index_0 = 3, #_list_0 do - local action = _list_0[_index_0] + for _index_0 = 3, #node do + local action = node[_index_0] _with_0:append(chain_item(action)) end actions = _with_0 diff --git a/moonscript/errors.lua b/moonscript/errors.lua index 91a91a10..f8d3254a 100644 --- a/moonscript/errors.lua +++ b/moonscript/errors.lua @@ -50,10 +50,9 @@ truncate_traceback = function(traceback, chunk_func) do local _accum_0 = { } local _len_0 = 1 - local _list_0 = traceback local _max_0 = stop - for _index_0 = 1, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do - local t = _list_0[_index_0] + for _index_0 = 1, _max_0 < 0 and #traceback + _max_0 or _max_0 do + local t = traceback[_index_0] _accum_0[_len_0] = t _len_0 = _len_0 + 1 end diff --git a/moonscript/transform.lua b/moonscript/transform.lua index f1e16de8..09a8aa23 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -854,9 +854,8 @@ Statement = Transformer({ if "stm" == _exp_0 then insert(statements, item[2]) elseif "props" == _exp_0 then - local _list_0 = item - for _index_1 = 2, #_list_0 do - local tuple = _list_0[_index_1] + for _index_1 = 2, #item do + local tuple = item[_index_1] if ntype(tuple[1]) == "self" then insert(statements, build.assign_one(unpack(tuple))) else @@ -1074,9 +1073,8 @@ Statement = Transformer({ do local _accum_0 = { } local _len_0 = 1 - local _list_0 = chain - for _index_0 = 3, #_list_0 do - local item = _list_0[_index_0] + for _index_0 = 3, #chain do + local item = chain[_index_0] _accum_0[_len_0] = item _len_0 = _len_0 + 1 end From c8d671a93137ee08104aec279491fb1695aefaeb Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 30 Jun 2013 23:28:51 -0700 Subject: [PATCH 140/554] no temporary functions when returning block_exp --- moon/init.lua | 12 +++++----- moonscript/compile.lua | 18 +++++++-------- moonscript/transform.lua | 26 +++++++++++++++++++++- moonscript/transform.moon | 27 +++++++++++++++++++++-- moonscript/util.lua | 16 ++++++-------- spec/outputs/bubbling.lua | 46 ++++++++++++++++++--------------------- spec/outputs/lists.lua | 34 +++++++++++++---------------- 7 files changed, 106 insertions(+), 73 deletions(-) diff --git a/moon/init.lua b/moon/init.lua index 5d80e525..0ca497c6 100644 --- a/moon/init.lua +++ b/moon/init.lua @@ -108,13 +108,11 @@ extend = function(...) return tbls[1] end copy = function(self) - return (function() - local _tbl_0 = { } - for key, val in pairs(self) do - _tbl_0[key] = val - end - return _tbl_0 - end)() + local _tbl_0 = { } + for key, val in pairs(self) do + _tbl_0[key] = val + end + return _tbl_0 end mixin = function(self, cls, ...) for key, val in pairs(cls.__base) do diff --git a/moonscript/compile.lua b/moonscript/compile.lua index 5892c20d..83f95cd9 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -119,16 +119,14 @@ do local strip strip = function(t) if "table" == type(t) then - return (function() - local _accum_0 = { } - local _len_0 = 1 - for _index_0 = 1, #t do - local v = t[_index_0] - _accum_0[_len_0] = strip(v) - _len_0 = _len_0 + 1 - end - return _accum_0 - end)() + local _accum_0 = { } + local _len_0 = 1 + for _index_0 = 1, #t do + local v = t[_index_0] + _accum_0[_len_0] = strip(v) + _len_0 = _len_0 + 1 + end + return _accum_0 else return t end diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 09a8aa23..4287c1d4 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -210,6 +210,18 @@ with_continue_listener = function(body) end do local _base_0 = { + transform_once = function(self, scope, node, ...) + if self.seen_nodes[node] then + return node + end + self.seen_nodes[node] = true + local transformer = self.transformers[ntype(node)] + if transformer then + return transformer(scope, node, ...) or node + else + return node + end + end, transform = function(self, scope, node, ...) if self.seen_nodes[node] then return node @@ -314,6 +326,18 @@ Statement = Transformer({ root_stms = function(self, body) return apply_to_last(body, implicitly_return(self)) end, + ["return"] = function(self, node) + node[2] = Value:transform_once(self, node[2]) + if "block_exp" == ntype(node[2]) then + local block_exp = node[2] + local block_body = block_exp[2] + local idx = #block_body + node[2] = block_body[idx] + block_body[idx] = node + return build.group(block_body) + end + return node + end, declare_glob = function(self, node) local names = extract_declarations(self) if node[2] == "^" then @@ -370,7 +394,7 @@ Statement = Transformer({ } }) elseif "comprehension" == _exp_0 or "tblcomprehension" == _exp_0 or "foreach" == _exp_0 or "for" == _exp_0 or "while" == _exp_0 then - return build.assign_one(first_name, Value.transformers[first_value[1]](self, first_value)) + return build.assign_one(first_name, Value:transform_once(self, first_value)) end end local transformed diff --git a/moonscript/transform.moon b/moonscript/transform.moon index 06671979..a7fcab6b 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -108,6 +108,16 @@ class Transformer new: (@transformers) => @seen_nodes = setmetatable {}, __mode: "k" + transform_once: (scope, node, ...) => + return node if @seen_nodes[node] + @seen_nodes[node] = true + + transformer = @transformers[ntype node] + if transformer + transformer(scope, node, ...) or node + else + node + transform: (scope, node, ...) => return node if @seen_nodes[node] @seen_nodes[node] = true @@ -158,6 +168,20 @@ Statement = Transformer { root_stms: (body) => apply_to_last body, implicitly_return @ + return: (node) => + node[2] = Value\transform_once @, node[2] + + if "block_exp" == ntype node[2] + block_exp = node[2] + block_body = block_exp[2] + + idx = #block_body + node[2] = block_body[idx] + block_body[idx] = node + return build.group block_body + + node + declare_glob: (node) => names = extract_declarations @ @@ -191,8 +215,7 @@ Statement = Transformer { } when "comprehension", "tblcomprehension", "foreach", "for", "while" - return build.assign_one first_name, - Value.transformers[first_value[1]] @, first_value + return build.assign_one first_name, Value\transform_once @, first_value -- bubble cascading assigns transformed = if num_values == 1 diff --git a/moonscript/util.lua b/moonscript/util.lua index 7e5631dc..dfb43557 100644 --- a/moonscript/util.lua +++ b/moonscript/util.lua @@ -77,15 +77,13 @@ split = function(str, delim) return { } end str = str .. delim - return (function() - local _accum_0 = { } - local _len_0 = 1 - for m in str:gmatch("(.-)" .. delim) do - _accum_0[_len_0] = m - _len_0 = _len_0 + 1 - end - return _accum_0 - end)() + local _accum_0 = { } + local _len_0 = 1 + for m in str:gmatch("(.-)" .. delim) do + _accum_0[_len_0] = m + _len_0 = _len_0 + 1 + end + return _accum_0 end local dump dump = function(what) diff --git a/spec/outputs/bubbling.lua b/spec/outputs/bubbling.lua index c0bc5fe7..247ff1c2 100644 --- a/spec/outputs/bubbling.lua +++ b/spec/outputs/bubbling.lua @@ -6,17 +6,15 @@ f = function(...) end local dont_bubble dont_bubble = function() - return (function() - local _accum_0 = { } - local _len_0 = 1 - for x in (function(...) - return print(...) - end)("hello") do - _accum_0[_len_0] = x - _len_0 = _len_0 + 1 - end - return _accum_0 - end)() + local _accum_0 = { } + local _len_0 = 1 + for x in (function(...) + return print(...) + end)("hello") do + _accum_0[_len_0] = x + _len_0 = _len_0 + 1 + end + return _accum_0 end local k do @@ -44,21 +42,19 @@ do end local m m = function(...) - return (function(...) - local _accum_0 = { } - local _len_0 = 1 - local _list_0 = { - ... - } - for _index_0 = 1, #_list_0 do - local x = _list_0[_index_0] - if f(...) > 4 then - _accum_0[_len_0] = x - _len_0 = _len_0 + 1 - end + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local x = _list_0[_index_0] + if f(...) > 4 then + _accum_0[_len_0] = x + _len_0 = _len_0 + 1 end - return _accum_0 - end)(...) + end + return _accum_0 end local x do diff --git a/spec/outputs/lists.lua b/spec/outputs/lists.lua index 7428af49..28461503 100644 --- a/spec/outputs/lists.lua +++ b/spec/outputs/lists.lua @@ -251,15 +251,13 @@ for _index_0 = a, _max_2 < 0 and #x + _max_2 or _max_2, c do end local normal normal = function(hello) - return (function() - local _accum_0 = { } - local _len_0 = 1 - for x in yeah do - _accum_0[_len_0] = x - _len_0 = _len_0 + 1 - end - return _accum_0 - end)() + local _accum_0 = { } + local _len_0 = 1 + for x in yeah do + _accum_0[_len_0] = x + _len_0 = _len_0 + 1 + end + return _accum_0 end local test = x(1, 2, 3, 4, 5) for _index_0 = 1, #test do @@ -281,14 +279,12 @@ _ = function() end end return function() - return (function() - local _accum_0 = { } - local _len_0 = 1 - for _index_0 = 1, #things do - x = things[_index_0] - _accum_0[_len_0] = x - _len_0 = _len_0 + 1 - end - return _accum_0 - end)() + local _accum_0 = { } + local _len_0 = 1 + for _index_0 = 1, #things do + x = things[_index_0] + _accum_0[_len_0] = x + _len_0 = _len_0 + 1 + end + return _accum_0 end \ No newline at end of file From 7b79c7caed048b5686e695d454dbef0f2b9043ec Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 30 Jun 2013 23:46:10 -0700 Subject: [PATCH 141/554] getting ready for 0.2.4 --- docs/reference.md | 2 +- docs/standard_lib.md | 2 +- moonscript/version.lua | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/reference.md b/docs/reference.md index 2d2b158f..b298b0e5 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -1,6 +1,6 @@ target: reference/index template: reference - title: MoonScript v0.2.3 - Language Guide + title: MoonScript v0.2.4 - Language Guide short_name: lang -- MoonScript is a programming language that compiles to diff --git a/docs/standard_lib.md b/docs/standard_lib.md index 566ffe7c..dc79d782 100644 --- a/docs/standard_lib.md +++ b/docs/standard_lib.md @@ -1,6 +1,6 @@ target: reference/standard_lib template: reference - title: MoonScript v0.2.3 - Standard Library + title: MoonScript v0.2.4 - Standard Library short_name: stdlib -- diff --git a/moonscript/version.lua b/moonscript/version.lua index e9595d0c..ce19da42 100644 --- a/moonscript/version.lua +++ b/moonscript/version.lua @@ -1,7 +1,7 @@ module("moonscript.version", package.seeall) -version = "0.2.3-2" +version = "0.2.4" function print_version() print("MoonScript version "..version) end From 6f097df524dc7c918cb268d9bf9750670d3805d4 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 30 Jun 2013 22:49:57 -0700 Subject: [PATCH 142/554] update docs --- docs/reference.md | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/docs/reference.md b/docs/reference.md index b298b0e5..6ed192df 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -18,6 +18,21 @@ homepage are located at . # The Language +## Whitespace + +MoonScript is a whitespace sensitive language. This means that +instead of using `do` and `end` (or `{` and `}`) to delimit sections of code we +use line-breaks and indentation. + +This means that how you indent you code is important. Luckily MoonScript +doesn't care how you do it but it's important to be consistent. + +An indent must be at least 1 space or 1 tab, but you can use as many as you +like. All the code snippets on this page will use two spaces. + +> Should you happen to mix tabs and spaces, a tab is equivalent to 4 spaces. I +> shouldn't be telling you this though because you should never do it. + ## Assignment Assigning to an undeclared name will cause it to be declared as a new local @@ -598,7 +613,7 @@ A `continue` statement can be used to skip the current iteration in a loop. ```moon i = 0 while i < 10 - continue if i % 2 ==0 + continue if i % 2 == 0 print i ``` `continue` can also be used with loop expressions to prevent that iteration @@ -1689,7 +1704,7 @@ A full list of flags can be seen by passing the `-h` or `--help` flag. # License (MIT) - Copyright (C) 2011 by Leaf Corcoran + Copyright (C) 2013 by Leaf Corcoran Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 9d7bb0c9733330c846e3b387b0ef60b21fa9f8fe Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Mon, 1 Jul 2013 11:48:47 -0700 Subject: [PATCH 143/554] update readme year --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index db9203c5..abfd3d39 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ busted ## License (MIT) -Copyright (C) 2012 by Leaf Corcoran +Copyright (C) 2013 by Leaf Corcoran Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 04a1d8207c9c450f5c50784ebe232f1442963cf1 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Mon, 1 Jul 2013 22:56:17 -0700 Subject: [PATCH 144/554] document unless --- docs/reference.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/reference.md b/docs/reference.md index 6ed192df..3aa30064 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -668,6 +668,17 @@ else print message -- prints: I am very tall ``` +The opposite of `if` is `unless`: + +```moon +unless os.date("%A") == "Monday" + print "it is not Monday!" +``` + +```moon +print "You're lucky!" unless math.random! > 0.1 +``` + ### With Assignment `if` and `elseif` blocks can take an assignment in place of a conditional From e57b0c1126b77f46a3cc9a81e8e11feb68ca623d Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 2 Jul 2013 09:15:00 -0700 Subject: [PATCH 145/554] fix statement doubling when implicitly returning an export --- moonscript/transform.lua | 5 ++++- moonscript/transform.moon | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 4287c1d4..bd30f770 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -462,7 +462,10 @@ Statement = Transformer({ }) else return build.group({ - node, + { + "export", + node[2] + }, build.assign({ names = node[2], values = node[3] diff --git a/moonscript/transform.moon b/moonscript/transform.moon index a7fcab6b..a1b0a9f7 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -263,8 +263,9 @@ Statement = Transformer { cls } else + -- pull out vawlues and assign them after the export build.group { - node + { "export", node[2] } build.assign { names: node[2] values: node[3] From d5599825e9a31290364a67b14f309fedc6fc52ab Mon Sep 17 00:00:00 2001 From: Jason Tu Date: Mon, 19 Aug 2013 16:30:36 -0400 Subject: [PATCH 146/554] Documentation fix: run_callback is defined, not called. --- docs/reference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference.md b/docs/reference.md index 3aa30064..2735bcf7 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -1439,7 +1439,7 @@ my_object = { write: => print "the value:", @value } -run_callback (func) -> +run_callback = (func) -> print "running callback..." func! From fd66fab0e4fe258b9336713fa1fbefa45a8d7889 Mon Sep 17 00:00:00 2001 From: Lee Miller Date: Sun, 8 Sep 2013 23:51:28 -0700 Subject: [PATCH 147/554] Fixing typo in docs. --- docs/standard_lib.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/standard_lib.md b/docs/standard_lib.md index dc79d782..95c2a552 100644 --- a/docs/standard_lib.md +++ b/docs/standard_lib.md @@ -81,7 +81,7 @@ values when a missing key is looked up. ### `extend(arg1, arg2, [rest...])` Chains together a series of tables by their metatable's `__index` property. -Overwrites the metatable of all objects exept for the last with a new table +Overwrites the metatable of all objects except for the last with a new table whose `__index` is set to the next table. Returns the first argument. From 0f4f01d000f4bb1e0fe29bfb7eb1d9c368776c58 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 6 Oct 2013 11:09:13 -0700 Subject: [PATCH 148/554] move everything into base.moon, expose insert_loader --- moonscript/base.lua | 114 +++++++++++++++++++++++++++++++++++++++++- moonscript/base.moon | 91 +++++++++++++++++++++++++++++++++- moonscript/init.lua | 115 ++----------------------------------------- moonscript/init.moon | 93 +--------------------------------- 4 files changed, 206 insertions(+), 207 deletions(-) diff --git a/moonscript/base.lua b/moonscript/base.lua index 2636187f..7d074c09 100644 --- a/moonscript/base.lua +++ b/moonscript/base.lua @@ -1,2 +1,112 @@ -_G.moon_no_loader = true -return require("moonscript") +local compile = require("moonscript.compile") +local parse = require("moonscript.parse") +local concat, insert +do + local _obj_0 = table + concat, insert = _obj_0.concat, _obj_0.insert +end +local split, dump, get_options, unpack +do + local _obj_0 = require("moonscript.util") + split, dump, get_options, unpack = _obj_0.split, _obj_0.dump, _obj_0.get_options, _obj_0.unpack +end +local lua = { + loadstring = loadstring, + load = load +} +local dirsep, line_tables, create_moonpath, to_lua, moon_loader, loadstring, loadfile, dofile, insert_loader +dirsep = "/" +line_tables = require("moonscript.line_tables") +create_moonpath = function(package_path) + local paths = split(package_path, ";") + for i, path in ipairs(paths) do + local p = path:match("^(.-)%.lua$") + if p then + paths[i] = p .. ".moon" + end + end + return concat(paths, ";") +end +to_lua = function(text, options) + if options == nil then + options = { } + end + if "string" ~= type(text) then + local t = type(text) + return nil, "expecting string (got " .. t .. ")", 2 + end + local tree, err = parse.string(text) + if not tree then + return nil, err + end + local code, ltable, pos = compile.tree(tree, options) + if not code then + return nil, compile.format_error(ltable, pos, text), 2 + end + return code, ltable +end +moon_loader = function(name) + local name_path = name:gsub("%.", dirsep) + local file, file_path + local _list_0 = split(package.moonpath, ";") + for _index_0 = 1, #_list_0 do + local path = _list_0[_index_0] + file_path = path:gsub("?", name_path) + file = io.open(file_path) + if file then + break + end + end + if file then + local text = file:read("*a") + file:close() + return loadstring(text, file_path) + else + return nil, "Could not find moon file" + end +end +loadstring = function(...) + local options, str, chunk_name, mode, env = get_options(...) + chunk_name = chunk_name or "=(moonscript.loadstring)" + local code, ltable_or_err = to_lua(str, options) + if not (code) then + return nil, ltable_or_err + end + if chunk_name then + line_tables[chunk_name] = ltable_or_err + end + return (lua.loadstring or lua.load)(code, chunk_name, unpack({ + mode, + env + })) +end +loadfile = function(fname, ...) + local file, err = io.open(fname) + if not (file) then + return nil, err + end + local text = assert(file:read("*a")) + file:close() + return loadstring(text, fname, ...) +end +dofile = function(...) + local f = assert(loadfile(...)) + return f() +end +insert_loader = function() + if not package.moonpath then + package.moonpath = create_moonpath(package.path) + end + return insert(package.loaders or package.searchers, 2, moon_loader) +end +return { + _NAME = "moonscript", + insert_loader = insert_loader, + to_lua = to_lua, + moon_chunk = moon_chunk, + moon_loader = moon_loader, + dirsep = dirsep, + dofile = dofile, + loadfile = loadfile, + loadstring = loadstring +} diff --git a/moonscript/base.moon b/moonscript/base.moon index b5fae84f..fc229290 100644 --- a/moonscript/base.moon +++ b/moonscript/base.moon @@ -1,2 +1,89 @@ -_G.moon_no_loader = true -require "moonscript" +compile = require "moonscript.compile" +parse = require "moonscript.parse" + +import concat, insert from table +import split, dump, get_options, unpack from require "moonscript.util" + +lua = :loadstring, :load + +local * + +dirsep = "/" +line_tables = require "moonscript.line_tables" + +-- create moon path package from lua package path +create_moonpath = (package_path) -> + paths = split package_path, ";" + for i, path in ipairs paths + p = path\match "^(.-)%.lua$" + if p then paths[i] = p..".moon" + concat paths, ";" + +to_lua = (text, options={}) -> + if "string" != type text + t = type text + return nil, "expecting string (got ".. t ..")", 2 + + tree, err = parse.string text + if not tree + return nil, err + + code, ltable, pos = compile.tree tree, options + if not code + return nil, compile.format_error(ltable, pos, text), 2 + + code, ltable + +moon_loader = (name) -> + name_path = name\gsub "%.", dirsep + + local file, file_path + for path in *split package.moonpath, ";" + file_path = path\gsub "?", name_path + file = io.open file_path + break if file + + if file + text = file\read "*a" + file\close! + loadstring text, file_path + else + nil, "Could not find moon file" + + +loadstring = (...) -> + options, str, chunk_name, mode, env = get_options ... + chunk_name or= "=(moonscript.loadstring)" + + code, ltable_or_err = to_lua str, options + unless code + return nil, ltable_or_err + + line_tables[chunk_name] = ltable_or_err if chunk_name + -- the unpack prevents us from passing nil + (lua.loadstring or lua.load) code, chunk_name, unpack { mode, env } + +loadfile = (fname, ...) -> + file, err = io.open fname + return nil, err unless file + text = assert file\read "*a" + file\close! + loadstring text, fname, ... + +-- throws errros +dofile = (...) -> + f = assert loadfile ... + f! + +insert_loader = -> + if not package.moonpath + package.moonpath = create_moonpath package.path + + insert package.loaders or package.searchers, 2, moon_loader + +{ + _NAME: "moonscript" + :insert_loader, :to_lua, :moon_chunk, :moon_loader, :dirsep, :dofile, + :loadfile, :loadstring +} + diff --git a/moonscript/init.lua b/moonscript/init.lua index 1d31f800..6de5f120 100644 --- a/moonscript/init.lua +++ b/moonscript/init.lua @@ -1,114 +1,5 @@ -local compile = require("moonscript.compile") -local parse = require("moonscript.parse") -local concat, insert do - local _obj_0 = table - concat, insert = _obj_0.concat, _obj_0.insert + local _with_0 = require("moonscript.base") + _with_0.insert_loader() + return _with_0 end -local split, dump, get_options, unpack -do - local _obj_0 = require("moonscript.util") - split, dump, get_options, unpack = _obj_0.split, _obj_0.dump, _obj_0.get_options, _obj_0.unpack -end -local lua = { - loadstring = loadstring, - load = load -} -local dirsep, line_tables, create_moonpath, to_lua, moon_loader, init_loader, loadstring, loadfile, dofile -dirsep = "/" -line_tables = require("moonscript.line_tables") -create_moonpath = function(package_path) - local paths = split(package_path, ";") - for i, path in ipairs(paths) do - local p = path:match("^(.-)%.lua$") - if p then - paths[i] = p .. ".moon" - end - end - return concat(paths, ";") -end -to_lua = function(text, options) - if options == nil then - options = { } - end - if "string" ~= type(text) then - local t = type(text) - return nil, "expecting string (got " .. t .. ")", 2 - end - local tree, err = parse.string(text) - if not tree then - return nil, err - end - local code, ltable, pos = compile.tree(tree, options) - if not code then - return nil, compile.format_error(ltable, pos, text), 2 - end - return code, ltable -end -moon_loader = function(name) - local name_path = name:gsub("%.", dirsep) - local file, file_path - local _list_0 = split(package.moonpath, ";") - for _index_0 = 1, #_list_0 do - local path = _list_0[_index_0] - file_path = path:gsub("?", name_path) - file = io.open(file_path) - if file then - break - end - end - if file then - local text = file:read("*a") - file:close() - return loadstring(text, file_path) - else - return nil, "Could not find moon file" - end -end -if not package.moonpath then - package.moonpath = create_moonpath(package.path) -end -init_loader = function() - return insert(package.loaders or package.searchers, 2, moon_loader) -end -if not (_G.moon_no_loader) then - init_loader() -end -loadstring = function(...) - local options, str, chunk_name, mode, env = get_options(...) - chunk_name = chunk_name or "=(moonscript.loadstring)" - local code, ltable_or_err = to_lua(str, options) - if not (code) then - return nil, ltable_or_err - end - if chunk_name then - line_tables[chunk_name] = ltable_or_err - end - return (lua.loadstring or lua.load)(code, chunk_name, unpack({ - mode, - env - })) -end -loadfile = function(fname, ...) - local file, err = io.open(fname) - if not (file) then - return nil, err - end - local text = assert(file:read("*a")) - file:close() - return loadstring(text, fname, ...) -end -dofile = function(...) - local f = assert(loadfile(...)) - return f() -end -return { - _NAME = "moonscript", - to_lua = to_lua, - moon_chunk = moon_chunk, - moon_loader = moon_loader, - dirsep = dirsep, - dofile = dofile, - loadfile = loadfile, - loadstring = loadstring -} diff --git a/moonscript/init.moon b/moonscript/init.moon index 2c9fe413..396686d6 100644 --- a/moonscript/init.moon +++ b/moonscript/init.moon @@ -1,91 +1,2 @@ - -compile = require "moonscript.compile" -parse = require "moonscript.parse" - -import concat, insert from table -import split, dump, get_options, unpack from require "moonscript.util" - -lua = :loadstring, :load - -local * - -dirsep = "/" -line_tables = require "moonscript.line_tables" - --- create moon path package from lua package path -create_moonpath = (package_path) -> - paths = split package_path, ";" - for i, path in ipairs paths - p = path\match "^(.-)%.lua$" - if p then paths[i] = p..".moon" - concat paths, ";" - -to_lua = (text, options={}) -> - if "string" != type text - t = type text - return nil, "expecting string (got ".. t ..")", 2 - - tree, err = parse.string text - if not tree - return nil, err - - code, ltable, pos = compile.tree tree, options - if not code - return nil, compile.format_error(ltable, pos, text), 2 - - code, ltable - -moon_loader = (name) -> - name_path = name\gsub "%.", dirsep - - local file, file_path - for path in *split package.moonpath, ";" - file_path = path\gsub "?", name_path - file = io.open file_path - break if file - - if file - text = file\read "*a" - file\close! - loadstring text, file_path - else - nil, "Could not find moon file" - -if not package.moonpath - package.moonpath = create_moonpath package.path - -init_loader = -> - insert package.loaders or package.searchers, 2, moon_loader - -init_loader! unless _G.moon_no_loader - -loadstring = (...) -> - options, str, chunk_name, mode, env = get_options ... - chunk_name or= "=(moonscript.loadstring)" - - code, ltable_or_err = to_lua str, options - unless code - return nil, ltable_or_err - - line_tables[chunk_name] = ltable_or_err if chunk_name - -- the unpack prevents us from passing nil - (lua.loadstring or lua.load) code, chunk_name, unpack { mode, env } - -loadfile = (fname, ...) -> - file, err = io.open fname - return nil, err unless file - text = assert file\read "*a" - file\close! - loadstring text, fname, ... - --- throws errros -dofile = (...) -> - f = assert loadfile ... - f! - -{ - _NAME: "moonscript" - :to_lua, :moon_chunk, :moon_loader, :dirsep, :dofile, :loadfile, - :loadstring -} - +with require "moonscript.base" + .insert_loader! From 99437bfd4c439887c6b1865c7b376761bf2a8bce Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 6 Oct 2013 11:30:15 -0700 Subject: [PATCH 149/554] add remove_loader function --- moonscript/base.lua | 32 +++++++++++++++++++++++++++----- moonscript/base.moon | 25 ++++++++++++++++++++----- 2 files changed, 47 insertions(+), 10 deletions(-) diff --git a/moonscript/base.lua b/moonscript/base.lua index 7d074c09..d3f83c22 100644 --- a/moonscript/base.lua +++ b/moonscript/base.lua @@ -1,9 +1,9 @@ local compile = require("moonscript.compile") local parse = require("moonscript.parse") -local concat, insert +local concat, insert, remove do local _obj_0 = table - concat, insert = _obj_0.concat, _obj_0.insert + concat, insert, remove = _obj_0.concat, _obj_0.insert, _obj_0.remove end local split, dump, get_options, unpack do @@ -14,7 +14,7 @@ local lua = { loadstring = loadstring, load = load } -local dirsep, line_tables, create_moonpath, to_lua, moon_loader, loadstring, loadfile, dofile, insert_loader +local dirsep, line_tables, create_moonpath, to_lua, moon_loader, loadstring, loadfile, dofile, insert_loader, remove_loader dirsep = "/" line_tables = require("moonscript.line_tables") create_moonpath = function(package_path) @@ -93,15 +93,37 @@ dofile = function(...) local f = assert(loadfile(...)) return f() end -insert_loader = function() +insert_loader = function(pos) + if pos == nil then + pos = 2 + end if not package.moonpath then package.moonpath = create_moonpath(package.path) end - return insert(package.loaders or package.searchers, 2, moon_loader) + local loaders = package.loaders or package.searchers + for _index_0 = 1, #loaders do + local loader = loaders[_index_0] + if loader == moon_loader then + return false + end + end + insert(loaders, pos, moon_loader) + return true +end +remove_loader = function() + local loaders = package.loaders or package.searchers + for i, loader in ipairs(loaders) do + if loader == moon_loader then + remove(loaders, i) + return true + end + end + return false end return { _NAME = "moonscript", insert_loader = insert_loader, + remove_loader = remove_loader, to_lua = to_lua, moon_chunk = moon_chunk, moon_loader = moon_loader, diff --git a/moonscript/base.moon b/moonscript/base.moon index fc229290..4e3e9315 100644 --- a/moonscript/base.moon +++ b/moonscript/base.moon @@ -1,7 +1,7 @@ compile = require "moonscript.compile" parse = require "moonscript.parse" -import concat, insert from table +import concat, insert, remove from table import split, dump, get_options, unpack from require "moonscript.util" lua = :loadstring, :load @@ -75,15 +75,30 @@ dofile = (...) -> f = assert loadfile ... f! -insert_loader = -> +insert_loader = (pos=2) -> if not package.moonpath package.moonpath = create_moonpath package.path - insert package.loaders or package.searchers, 2, moon_loader + loaders = package.loaders or package.searchers + for loader in *loaders + return false if loader == moon_loader + + insert loaders, pos, moon_loader + true + +remove_loader = -> + loaders = package.loaders or package.searchers + + for i, loader in ipairs loaders + if loader == moon_loader + remove loaders, i + return true + + false { _NAME: "moonscript" - :insert_loader, :to_lua, :moon_chunk, :moon_loader, :dirsep, :dofile, - :loadfile, :loadstring + :insert_loader, :remove_loader, :to_lua, :moon_chunk, :moon_loader, :dirsep, + :dofile, :loadfile, :loadstring } From cc6cb70ef6623a7ba4923f5e9044bdd8cb05c264 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 6 Oct 2013 12:17:17 -0700 Subject: [PATCH 150/554] only have loader active when running chunk --- bin/moon | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/bin/moon b/bin/moon index 5ce9d414..ca050fc2 100755 --- a/bin/moon +++ b/bin/moon @@ -1,7 +1,7 @@ #!/usr/bin/env lua require "alt_getopt" -local moonscript = require "moonscript" +local moonscript = require "moonscript.base" local util = require "moonscript.util" local errors = require "moonscript.errors" @@ -70,10 +70,17 @@ end util.getfenv(moonscript_chunk).arg = new_arg +local function run_chunk() + moonscript.insert_loader() + moonscript_chunk(unpack(new_arg)) + moonscript.remove_loader() +end + if not opts.d then local err, trace xpcall(function() moonscript_chunk(unpack(new_arg)) end, function(_err) + xpcall(run_chunk, function(_err) err = _err trace = debug.traceback("", 2) end) @@ -93,5 +100,5 @@ if not opts.d then end end else - moonscript_chunk(unpack(new_arg)) + run_chunk() end From ae0de2a141a33da8eee364623053464d1021dc9a Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 6 Oct 2013 12:56:52 -0700 Subject: [PATCH 151/554] commit typo --- bin/moon | 1 - 1 file changed, 1 deletion(-) diff --git a/bin/moon b/bin/moon index ca050fc2..0818d23d 100755 --- a/bin/moon +++ b/bin/moon @@ -79,7 +79,6 @@ end if not opts.d then local err, trace - xpcall(function() moonscript_chunk(unpack(new_arg)) end, function(_err) xpcall(run_chunk, function(_err) err = _err trace = debug.traceback("", 2) From 6a01d4c6533d21b8dce6c1a88956d909b8f7c0bc Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 8 Oct 2013 00:14:14 -0700 Subject: [PATCH 152/554] code coverage flag --- bin/moon | 12 +++ moonscript/cmd/coverage.lua | 138 +++++++++++++++++++++++++++++++++++ moonscript/cmd/coverage.moon | 76 +++++++++++++++++++ 3 files changed, 226 insertions(+) create mode 100644 moonscript/cmd/coverage.lua create mode 100644 moonscript/cmd/coverage.moon diff --git a/bin/moon b/bin/moon index 0818d23d..8ce49827 100755 --- a/bin/moon +++ b/bin/moon @@ -15,6 +15,7 @@ local help = [=[Usage: %s [options] [script [args]] -h Print this message -d Disable stack trace rewriting + -c Collect and print code coverage -v Print version ]=] @@ -78,6 +79,13 @@ end if not opts.d then local err, trace + local cov + + if opts.c then + local coverage = require "moonscript.cmd.coverage" + cov = coverage.CodeCoverage() + cov:start() + end xpcall(run_chunk, function(_err) err = _err @@ -97,6 +105,10 @@ if not opts.d then util.trim(trace) }, "\n")) end + else + if cov then + cov:stop() + end end else run_chunk() diff --git a/moonscript/cmd/coverage.lua b/moonscript/cmd/coverage.lua new file mode 100644 index 00000000..be4923d4 --- /dev/null +++ b/moonscript/cmd/coverage.lua @@ -0,0 +1,138 @@ +local moon = require("moon") +local log +log = function(str) + if str == nil then + str = "" + end + return io.stderr:write(str .. "\n") +end +local create_counter +create_counter = function() + return setmetatable({ }, { + __index = function(self, name) + do + local tbl = setmetatable({ }, { + __index = function(self) + return 0 + end + }) + self[name] = tbl + return tbl + end + end + }) +end +local position_to_lines +position_to_lines = function(file_content, positions) + local lines = { } + local current_pos = 0 + local line_no = 1 + for char in file_content:gmatch(".") do + do + local count = rawget(positions, current_pos) + if count then + lines[line_no] = count + end + end + if char == "\n" then + line_no = line_no + 1 + end + current_pos = current_pos + 1 + end + return lines +end +local format_file +format_file = function(fname, positions) + local file = assert(io.open(fname)) + local content = file:read("*a") + file:close() + local lines = position_to_lines(content, positions) + log("------| @" .. tostring(fname)) + local line_no = 1 + for line in (content .. "\n"):gmatch("(.-)\n") do + local foramtted_no = ("% 5d"):format(line_no) + local sym = lines[line_no] and "*" or " " + log(tostring(sym) .. tostring(foramtted_no) .. "| " .. tostring(line)) + line_no = line_no + 1 + end + return log() +end +local CodeCoverage +do + local _base_0 = { + start = function(self) + self.line_counts = create_counter() + return debug.sethook((function() + local _base_1 = self + local _fn_0 = _base_1.process_line + return function(...) + return _fn_0(_base_1, ...) + end + end)(), "l") + end, + stop = function(self) + debug.sethook() + local line_table = require("moonscript.line_tables") + return self:format_results() + end, + process_line = function(self, _, line_no) + local debug_data = debug.getinfo(2, "S") + local source = debug_data.source + self.line_counts[source][line_no] = self.line_counts[source][line_no] + 1 + end, + format_results = function(self) + local line_table = require("moonscript.line_tables") + local positions = create_counter() + for file, lines in pairs(self.line_counts) do + local _continue_0 = false + repeat + local file_table = line_table[file] + if not (file_table) then + _continue_0 = true + break + end + for line, count in pairs(lines) do + local _continue_1 = false + repeat + local position = file_table[line] + if not (position) then + _continue_1 = true + break + end + positions[file][position] = positions[file][position] + count + _continue_1 = true + until true + if not _continue_1 then + break + end + end + _continue_0 = true + until true + if not _continue_0 then + break + end + end + for file, ps in pairs(positions) do + format_file(file, ps) + end + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function() end, + __base = _base_0, + __name = "CodeCoverage" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + CodeCoverage = _class_0 +end +return { + CodeCoverage = CodeCoverage +} diff --git a/moonscript/cmd/coverage.moon b/moonscript/cmd/coverage.moon new file mode 100644 index 00000000..5066406b --- /dev/null +++ b/moonscript/cmd/coverage.moon @@ -0,0 +1,76 @@ + +moon = require "moon" + +log = (str="") -> + io.stderr\write str .. "\n" + +create_counter = -> + setmetatable {}, __index: (name) => + with tbl = setmetatable {}, __index: => 0 + @[name] = tbl + +position_to_lines = (file_content, positions) -> + lines = {} + current_pos = 0 + line_no = 1 + for char in file_content\gmatch "." + if count = rawget positions, current_pos + lines[line_no] = count + + if char == "\n" + line_no += 1 + + current_pos += 1 + + lines + +format_file = (fname, positions) -> + file = assert io.open fname + content = file\read "*a" + file\close! + + lines = position_to_lines content, positions + log "------| @#{fname}" + line_no = 1 + for line in (content .. "\n")\gmatch "(.-)\n" + foramtted_no = "% 5d"\format(line_no) + sym = lines[line_no] and "*" or " " + log "#{sym}#{foramtted_no}| #{line}" + line_no += 1 + + log! + + +class CodeCoverage + start: => + @line_counts = create_counter! + debug.sethook @\process_line, "l" + + stop: => + debug.sethook! + line_table = require "moonscript.line_tables" + + @format_results! + + process_line: (_, line_no) => + debug_data = debug.getinfo 2, "S" + source = debug_data.source + @line_counts[source][line_no] += 1 + + format_results: => + line_table = require "moonscript.line_tables" + positions = create_counter! + + for file, lines in pairs @line_counts + file_table = line_table[file] + continue unless file_table + + for line, count in pairs lines + position = file_table[line] + continue unless position + positions[file][position] += count + + for file, ps in pairs positions + format_file file, ps + +{ :CodeCoverage } From eb8788cb89ab698257dbe702a3c4716c64977b14 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 8 Oct 2013 00:18:17 -0700 Subject: [PATCH 153/554] remove moon --- moonscript/cmd/coverage.lua | 1 - moonscript/cmd/coverage.moon | 2 -- 2 files changed, 3 deletions(-) diff --git a/moonscript/cmd/coverage.lua b/moonscript/cmd/coverage.lua index be4923d4..daac16f9 100644 --- a/moonscript/cmd/coverage.lua +++ b/moonscript/cmd/coverage.lua @@ -1,4 +1,3 @@ -local moon = require("moon") local log log = function(str) if str == nil then diff --git a/moonscript/cmd/coverage.moon b/moonscript/cmd/coverage.moon index 5066406b..55e6a783 100644 --- a/moonscript/cmd/coverage.moon +++ b/moonscript/cmd/coverage.moon @@ -1,6 +1,4 @@ -moon = require "moon" - log = (str="") -> io.stderr\write str .. "\n" From 4ccc10d05692b6bd3a1595603a6bd7508e482507 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 9 Oct 2013 14:24:13 -0700 Subject: [PATCH 154/554] pause and resume coverage --- bin/moon | 1 + moonscript/cmd/coverage.lua | 13 +++++++++---- moonscript/cmd/coverage.moon | 9 +++++++-- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/bin/moon b/bin/moon index 8ce49827..b6ef27fe 100755 --- a/bin/moon +++ b/bin/moon @@ -108,6 +108,7 @@ if not opts.d then else if cov then cov:stop() + cov:print_results() end end else diff --git a/moonscript/cmd/coverage.lua b/moonscript/cmd/coverage.lua index daac16f9..8c585e83 100644 --- a/moonscript/cmd/coverage.lua +++ b/moonscript/cmd/coverage.lua @@ -59,8 +59,10 @@ end local CodeCoverage do local _base_0 = { - start = function(self) + reset = function(self) self.line_counts = create_counter() + end, + start = function(self) return debug.sethook((function() local _base_1 = self local _fn_0 = _base_1.process_line @@ -70,8 +72,9 @@ do end)(), "l") end, stop = function(self) - debug.sethook() - local line_table = require("moonscript.line_tables") + return debug.sethook() + end, + print_results = function(self) return self:format_results() end, process_line = function(self, _, line_no) @@ -118,7 +121,9 @@ do } _base_0.__index = _base_0 local _class_0 = setmetatable({ - __init = function() end, + __init = function(self) + return self:reset() + end, __base = _base_0, __name = "CodeCoverage" }, { diff --git a/moonscript/cmd/coverage.moon b/moonscript/cmd/coverage.moon index 55e6a783..dd1d1fa0 100644 --- a/moonscript/cmd/coverage.moon +++ b/moonscript/cmd/coverage.moon @@ -40,14 +40,19 @@ format_file = (fname, positions) -> class CodeCoverage - start: => + new: => + @reset! + + reset: => @line_counts = create_counter! + + start: => debug.sethook @\process_line, "l" stop: => debug.sethook! - line_table = require "moonscript.line_tables" + print_results: => @format_results! process_line: (_, line_no) => From d63649c4a6dad6952c3ecfe87847e81aec0e955d Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 9 Oct 2013 14:31:55 -0700 Subject: [PATCH 155/554] coverage to rockspec --- moonscript-dev-1.rockspec | 1 + 1 file changed, 1 insertion(+) diff --git a/moonscript-dev-1.rockspec b/moonscript-dev-1.rockspec index a5323882..a83ad92d 100644 --- a/moonscript-dev-1.rockspec +++ b/moonscript-dev-1.rockspec @@ -26,6 +26,7 @@ build = { ["moon.all"] = "moon/all.lua", ["moonscript"] = "moonscript/init.lua", ["moonscript.base"] = "moonscript/base.lua", + ["moonscript.cmd.coverage"] = "moonscript/cmd/coverage.lua", ["moonscript.compile"] = "moonscript/compile.lua", ["moonscript.compile.statement"] = "moonscript/compile/statement.lua", ["moonscript.compile.value"] = "moonscript/compile/value.lua", From 24947cf3d3c3e9d3795ead888b036a418dfc75bc Mon Sep 17 00:00:00 2001 From: James Rowe Date: Wed, 20 Nov 2013 04:12:08 +0000 Subject: [PATCH 156/554] Fix very minor typos --- docs/reference.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/reference.md b/docs/reference.md index 2735bcf7..aab65d09 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -8,7 +8,7 @@ MoonScript is a programming language that compiles to familiarity with Lua. For each code snippet below, the MoonScript is on the left and the compiled Lua is on right right. -This is the offical language reference manual, installation directions and the +This is the official language reference manual, installation directions and the homepage are located at .
@@ -130,7 +130,7 @@ argument names in parentheses: sum = (x, y) -> print "sum", x + y ``` -Functions can be called by listing the arguments after the name of an expresion +Functions can be called by listing the arguments after the name of an expression that evaluates to a function. When chaining together function calls, the arguments are applied to the closest function to the left. @@ -727,7 +727,7 @@ is done with the `==` operator. name = "Dan" switch name when "Robert" - print "You are robert" + print "You are Robert" when "Dan", "Daniel" print "Your name, it's Dan" else From cc534a01f3919eb493f3726d783cc69c3cee1922 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 26 Dec 2013 01:29:00 -0800 Subject: [PATCH 157/554] create a basic lint tool --- bin/moonc | 14 +++- moonscript/cmd/lint.lua | 145 +++++++++++++++++++++++++++++++++++++++ moonscript/cmd/lint.moon | 72 +++++++++++++++++++ moonscript/compile.lua | 5 +- moonscript/compile.moon | 6 +- 5 files changed, 236 insertions(+), 6 deletions(-) create mode 100644 moonscript/cmd/lint.lua create mode 100644 moonscript/cmd/lint.moon diff --git a/bin/moonc b/bin/moonc index d7a92206..ed7f5272 100755 --- a/bin/moonc +++ b/bin/moonc @@ -9,8 +9,8 @@ local dump_tree = require"moonscript.dump".tree local alt_getopt = require "alt_getopt" local lfs = require "lfs" -local opts, ind = alt_getopt.get_opts(arg, "vhwt:pTXb", { - print = "p", tree = "T", version = "v", help = "h" +local opts, ind = alt_getopt.get_opts(arg, "lvhwt:pTXb", { + print = "p", tree = "T", version = "v", help = "h", lint = "l" }) local read_stdin = arg[1] == "--" @@ -25,6 +25,7 @@ local help = [[Usage: %s [options] files... -p Write output to standard out -T Write parse tree instead of code (to stdout) -X Write line rewrite map instead of code (to stdout) + -l Perform lint on the file instead of compiling -b Dump parse and compile time (doesn't write output) -v Print version @@ -377,6 +378,15 @@ if opts.w then end print "\nQuitting..." +elseif opts.l then + for _, fname in pairs(files) do + lint = require "moonscript.cmd.lint" + local res = lint.lint_file(fname) + if res then + print(res) + print() + end + end else for _, fname in ipairs(files) do local success, err = compile_and_write(fname, target_dir..convert_path(fname)) diff --git a/moonscript/cmd/lint.lua b/moonscript/cmd/lint.lua new file mode 100644 index 00000000..24e144a6 --- /dev/null +++ b/moonscript/cmd/lint.lua @@ -0,0 +1,145 @@ +local insert +do + local _obj_0 = table + insert = _obj_0.insert +end +local Set +do + local _obj_0 = require("moonscript.data") + Set = _obj_0.Set +end +local Block +do + local _obj_0 = require("moonscript.compile") + Block = _obj_0.Block +end +local whitelist_globals = Set({ + "print" +}) +local LinterBlock +do + local _parent_0 = Block + local _base_0 = { + block = function(self, ...) + do + local _with_0 = _parent_0.block(self, ...) + _with_0.value_compilers = self.value_compilers + return _with_0 + end + end + } + _base_0.__index = _base_0 + setmetatable(_base_0, _parent_0.__base) + local _class_0 = setmetatable({ + __init = function(self, lint_errors, ...) + if lint_errors == nil then + lint_errors = { } + end + self.lint_errors = lint_errors + _parent_0.__init(self, ...) + local vc = self.value_compilers + self.value_compilers = setmetatable({ + raw_value = function(block, name) + if name:match("^[%w_]+$") and not block:has_name(name) and not whitelist_globals[name] then + local stm = block.current_stms[block.current_stm_i] + insert(self.lint_errors, { + "accessing global " .. tostring(name), + stm[-1] + }) + end + return vc.raw_value(block, name) + end + }, { + __index = vc + }) + end, + __base = _base_0, + __name = "LinterBlock", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + LinterBlock = _class_0 +end +local format_lint +format_lint = function(errors, code, header) + if not (next(errors)) then + return + end + local pos_to_line, get_line + do + local _obj_0 = require("moonscript.util") + pos_to_line, get_line = _obj_0.pos_to_line, _obj_0.get_line + end + local formatted + do + local _accum_0 = { } + local _len_0 = 1 + for _index_0 = 1, #errors do + local _des_0 = errors[_index_0] + local msg, pos + msg, pos = _des_0[1], _des_0[2] + if pos then + local line = pos_to_line(code, pos) + msg = "line " .. tostring(line) .. ": " .. tostring(msg) + local line_text = "> " .. get_line(code, line) + local sep_len = math.max(#msg, #line_text) + _accum_0[_len_0] = table.concat({ + msg, + ("="):rep(sep_len), + line_text + }, "\n") + else + _accum_0[_len_0] = msg + end + _len_0 = _len_0 + 1 + end + formatted = _accum_0 + end + if header then + table.insert(formatted, 1, header) + end + return table.concat(formatted, "\n\n") +end +local lint_code +lint_code = function(code, name) + if name == nil then + name = "string input" + end + local parse = require("moonscript.parse") + local tree, err = parse.string(code) + if not (tree) then + return nil, err + end + local scope = LinterBlock() + scope:stms(tree) + return format_lint(scope.lint_errors, code, name) +end +local lint_file +lint_file = function(fname) + local f, err = io.open(fname) + if not (f) then + return nil, err + end + return lint_code(f:read("*a"), fname) +end +return { + lint_code = lint_code, + lint_file = lint_file +} diff --git a/moonscript/cmd/lint.moon b/moonscript/cmd/lint.moon new file mode 100644 index 00000000..dd3568d9 --- /dev/null +++ b/moonscript/cmd/lint.moon @@ -0,0 +1,72 @@ + +import insert from table +import Set from require "moonscript.data" +import Block from require "moonscript.compile" + +-- globals allowed to be referenced +whitelist_globals = Set { + "print" +} + +class LinterBlock extends Block + new: (@lint_errors={}, ...) => + super ... + + vc = @value_compilers + @value_compilers = setmetatable { + raw_value: (block, name) -> + + if name\match("^[%w_]+$") and not block\has_name(name) and not whitelist_globals[name] + stm = block.current_stms[block.current_stm_i] + insert @lint_errors, { + "accessing global #{name}" + stm[-1] + } + + vc.raw_value block, name + }, __index: vc + + block: (...) => + with super ... + .value_compilers = @value_compilers + +format_lint = (errors, code, header) -> + return unless next errors + + import pos_to_line, get_line from require "moonscript.util" + formatted = for {msg, pos} in *errors + if pos + line = pos_to_line code, pos + msg = "line #{line}: #{msg}" + line_text = "> " .. get_line code, line + + sep_len = math.max #msg, #line_text + table.concat { + msg + "="\rep sep_len + line_text + }, "\n" + + else + msg + + table.insert formatted, 1, header if header + table.concat formatted, "\n\n" + + +lint_code = (code, name="string input") -> + parse = require "moonscript.parse" + tree, err = parse.string code + return nil, err unless tree + + scope = LinterBlock! + scope\stms tree + format_lint scope.lint_errors, code, name + +lint_file = (fname) -> + f, err = io.open fname + return nil, err unless f + lint_code f\read("*a"), fname + + +{ :lint_code, :lint_file } diff --git a/moonscript/compile.lua b/moonscript/compile.lua index 83f95cd9..0970eab3 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -271,6 +271,7 @@ do footer = "end", export_all = false, export_proper = false, + value_compilers = value_compilers, __tostring = function(self) local h if "string" == type(self.header) then @@ -459,7 +460,7 @@ do end, is_value = function(self, node) local t = ntype(node) - return value_compilers[t] ~= nil or t == "value" + return self.value_compilers[t] ~= nil or t == "value" end, name = function(self, node, ...) return self:value(node, ...) @@ -472,7 +473,7 @@ do else action = node[1] end - local fn = value_compilers[action] + local fn = self.value_compilers[action] if not fn then error("Failed to compile value: " .. dump.value(node)) end diff --git a/moonscript/compile.moon b/moonscript/compile.moon index 0d999460..33bb719a 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -161,6 +161,8 @@ class Block export_all: false export_proper: false + value_compilers: value_compilers + __tostring: => h = if "string" == type @header @header @@ -316,7 +318,7 @@ class Block is_value: (node) => t = ntype node - value_compilers[t] != nil or t == "value" + @value_compilers[t] != nil or t == "value" -- line wise compile functions name: (node, ...) => @value node, ... @@ -328,7 +330,7 @@ class Block else node[1] - fn = value_compilers[action] + fn = @value_compilers[action] error "Failed to compile value: "..dump.value node if not fn out = fn self, node, ... From 4cacbec0f8aca097b67b8e1adca50497988bbc99 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 26 Dec 2013 01:37:02 -0800 Subject: [PATCH 158/554] up rockspec --- moonscript-dev-1.rockspec | 1 + 1 file changed, 1 insertion(+) diff --git a/moonscript-dev-1.rockspec b/moonscript-dev-1.rockspec index a83ad92d..7fd5ef17 100644 --- a/moonscript-dev-1.rockspec +++ b/moonscript-dev-1.rockspec @@ -27,6 +27,7 @@ build = { ["moonscript"] = "moonscript/init.lua", ["moonscript.base"] = "moonscript/base.lua", ["moonscript.cmd.coverage"] = "moonscript/cmd/coverage.lua", + ["moonscript.cmd.lint"] = "moonscript/cmd/lint.lua", ["moonscript.compile"] = "moonscript/compile.lua", ["moonscript.compile.statement"] = "moonscript/compile/statement.lua", ["moonscript.compile.value"] = "moonscript/compile/value.lua", From 009bf8eff717ca0b381115d4c152e2aeb90361dd Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 26 Dec 2013 01:41:45 -0800 Subject: [PATCH 159/554] include all default globals --- moonscript/cmd/lint.lua | 38 +++++++++++++++++++++++++++++++++++++- moonscript/cmd/lint.moon | 38 +++++++++++++++++++++++++++++++++++++- 2 files changed, 74 insertions(+), 2 deletions(-) diff --git a/moonscript/cmd/lint.lua b/moonscript/cmd/lint.lua index 24e144a6..b47842bf 100644 --- a/moonscript/cmd/lint.lua +++ b/moonscript/cmd/lint.lua @@ -14,7 +14,43 @@ do Block = _obj_0.Block end local whitelist_globals = Set({ - "print" + 'loadstring', + 'select', + '_VERSION', + 'pcall', + 'package', + 'error', + 'rawget', + 'pairs', + 'xpcall', + 'rawlen', + 'io', + 'loadfile', + 'ipairs', + 'table', + 'require', + 'os', + 'module', + 'debug', + 'type', + 'getmetatable', + 'rawequal', + 'dofile', + 'unpack', + 'math', + 'load', + 'bit32', + 'string', + 'rawset', + 'tostring', + 'print', + 'assert', + '_G', + 'next', + 'setmetatable', + 'tonumber', + 'collectgarbage', + 'coroutine' }) local LinterBlock do diff --git a/moonscript/cmd/lint.moon b/moonscript/cmd/lint.moon index dd3568d9..b0fcd58e 100644 --- a/moonscript/cmd/lint.moon +++ b/moonscript/cmd/lint.moon @@ -5,7 +5,43 @@ import Block from require "moonscript.compile" -- globals allowed to be referenced whitelist_globals = Set { - "print" + 'loadstring' + 'select' + '_VERSION' + 'pcall' + 'package' + 'error' + 'rawget' + 'pairs' + 'xpcall' + 'rawlen' + 'io' + 'loadfile' + 'ipairs' + 'table' + 'require' + 'os' + 'module' + 'debug' + 'type' + 'getmetatable' + 'rawequal' + 'dofile' + 'unpack' + 'math' + 'load' + 'bit32' + 'string' + 'rawset' + 'tostring' + 'print' + 'assert' + '_G' + 'next' + 'setmetatable' + 'tonumber' + 'collectgarbage' + 'coroutine' } class LinterBlock extends Block From 18a3723f007510035b0651d7161f1ebfe1d5ec91 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 26 Dec 2013 22:44:54 -0800 Subject: [PATCH 160/554] write to stderr instead of stdout --- bin/moonc | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/bin/moonc b/bin/moonc index ed7f5272..0e2e2f78 100755 --- a/bin/moonc +++ b/bin/moonc @@ -40,9 +40,12 @@ if opts.v then end function print_help(err) - if err then print("Error: "..err) end - print(help:format(arg[0])) - os.exit() + if err then + io.stderr:write("Error: ".. err .. "\n") + end + + io.stderr:write(help:format(arg[0]) .. "\n") + os.exit(1) end function mkdir(path) @@ -70,9 +73,9 @@ function convert_path(path) return (path:gsub("%.moon$", ".lua")) end -function msg(...) +function log_msg(...) if not opts.p then - print(...) + io.stderr:write(table.concat({...}, " ") .. "\n") end end @@ -302,7 +305,7 @@ function create_watcher(files) dirs = remove_dups(dirs) return coroutine.wrap(function() - print(("%s with inotify [%s]"):format(msg, plural(#dirs, "dir"))) + io.stderr:write(("%s with inotify [%s]"):format(msg, plural(#dirs, "dir")) .. "\n") local wd_table = {} local handle = inotify.init() @@ -329,7 +332,7 @@ function create_watcher(files) -- poll the filesystem instead local sleep = get_sleep_func() return coroutine.wrap(function() - print(("%s with polling [%s]"):format(msg, plural(#files, "file"))) + io.stderr:write(("%s with polling [%s]"):format(msg, plural(#files, "file")) .. "\n") local mod_time = {} while true do @@ -368,33 +371,34 @@ if opts.w then local target = target_dir..convert_path(fname) local success, err = compile_and_write(fname, target) if not success then - print() - print("Error:", fname) - print(err) - print() + io.stderr:write(table.concat({ + "", + "Error: " .. fname, + err, + "\n", + }, "\n")) else - msg("Built:", fname, "->", target) + log_msg("Built:", fname, "->", target) end end - print "\nQuitting..." + io.stderr:write("\nQuitting...\n") elseif opts.l then for _, fname in pairs(files) do lint = require "moonscript.cmd.lint" local res = lint.lint_file(fname) if res then - print(res) - print() + io.stderr:write(res .. "\n\n") end end else for _, fname in ipairs(files) do local success, err = compile_and_write(fname, target_dir..convert_path(fname)) if not success then - print(fname, err) + io.stderr:write(fname .. "\t" .. err .. "\n") os.exit(1) else - msg("Built", fname) + log_msg("Built", fname) end end end From 5461bd179be52d71a3300c1b60dd408b151d8da7 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 26 Dec 2013 22:47:11 -0800 Subject: [PATCH 161/554] keep help on stdout unless error --- bin/moonc | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/bin/moonc b/bin/moonc index 0e2e2f78..7ce00f37 100755 --- a/bin/moonc +++ b/bin/moonc @@ -40,12 +40,16 @@ if opts.v then end function print_help(err) + local help_msg = help:format(arg[0]) + if err then io.stderr:write("Error: ".. err .. "\n") + io.stderr:write(help_msg .. "\n") + os.exit(1) + else + print(help_msg) + os.exit(0) end - - io.stderr:write(help:format(arg[0]) .. "\n") - os.exit(1) end function mkdir(path) From ec35fc03d2476ca060d0c5a533d3582b1731aadc Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 27 Dec 2013 00:30:03 -0800 Subject: [PATCH 162/554] delete invalid test --- spec/inputs/lists.moon | 2 -- spec/outputs/lists.lua | 10 ---------- 2 files changed, 12 deletions(-) diff --git a/spec/inputs/lists.moon b/spec/inputs/lists.moon index 48337cde..91e559e2 100644 --- a/spec/inputs/lists.moon +++ b/spec/inputs/lists.moon @@ -3,8 +3,6 @@ hi = [x*2 for _, x in ipairs{1,2,3,4}] items = {1,2,3,4,5,6} -mm = [@x for @x in ipairs items] - [z for z in ipairs items when z > 4] rad = [{a} for a in ipairs { diff --git a/spec/outputs/lists.lua b/spec/outputs/lists.lua index 28461503..81aaa5b9 100644 --- a/spec/outputs/lists.lua +++ b/spec/outputs/lists.lua @@ -21,16 +21,6 @@ local items = { 5, 6 } -local mm -do - local _accum_0 = { } - local _len_0 = 1 - for self.x in ipairs(items) do - _accum_0[_len_0] = self.x - _len_0 = _len_0 + 1 - end - mm = _accum_0 -end for z in ipairs(items) do if z > 4 then local _ = z From 09f4cea638197d98bfacfeb444c0500561c2f6d1 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 26 Dec 2013 23:07:24 -0800 Subject: [PATCH 163/554] add ref value type --- moonscript/compile/value.lua | 3 +++ moonscript/compile/value.moon | 4 ++++ moonscript/parse.lua | 4 ++-- moonscript/transform/destructure.lua | 6 +++--- moonscript/transform/destructure.moon | 14 +++++++------- 5 files changed, 19 insertions(+), 12 deletions(-) diff --git a/moonscript/compile/value.lua b/moonscript/compile/value.lua index d5494ea5..99b1b15a 100644 --- a/moonscript/compile/value.lua +++ b/moonscript/compile/value.lua @@ -293,6 +293,9 @@ local value_compilers = { self_class_colon = function(self, node) return "self.__class:" .. self:value(node[2]) end, + ref = function(self, value) + return tostring(value[2]) + end, raw_value = function(self, value) local sup = self:get("super") if value == "super" and sup then diff --git a/moonscript/compile/value.moon b/moonscript/compile/value.moon index 89b21e92..77e87c82 100644 --- a/moonscript/compile/value.moon +++ b/moonscript/compile/value.moon @@ -183,6 +183,10 @@ value_compilers = self_class_colon: (node) => "self.__class:"..@value node[2] + -- a variable reference + ref: (value) => + tostring value[2] + -- catch all pure string values raw_value: (value) => sup = @get"super" diff --git a/moonscript/parse.lua b/moonscript/parse.lua index e3966c74..34c1871c 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -175,7 +175,7 @@ local _chain_assignable = { index = true, dot = true, slice = true } local function is_assignable(node) local t = ntype(node) - return t == "self" or t == "value" or t == "self_class" or + return t == "ref" or t == "self" or t == "value" or t == "self_class" or t == "chain" and _chain_assignable[ntype(node[#node])] or t == "table" end @@ -511,7 +511,7 @@ local build_grammar = wrap_env(function() LuaStringOpen = sym"[" * P"="^0 * "[" / trim, LuaStringClose = "]" * P"="^0 * "]", - Callable = Name + Parens / mark"parens", + Callable = Name / mark"ref" + Parens / mark"parens", Parens = sym"(" * Exp * sym")", FnArgs = symx"(" * Ct(ExpList^-1) * sym")" + sym"!" * -P"=" * Ct"", diff --git a/moonscript/transform/destructure.lua b/moonscript/transform/destructure.lua index dcfa3970..cb450711 100644 --- a/moonscript/transform/destructure.lua +++ b/moonscript/transform/destructure.lua @@ -100,13 +100,13 @@ extract_assign_names = function(name, accum, prefix) suffix = join(prefix, { suffix }) - local t = ntype(value) - if t == "value" or t == "chain" or t == "self" then + local _exp_0 = ntype(value) + if "value" == _exp_0 or "ref" == _exp_0 or "chain" == _exp_0 or "self" == _exp_0 then insert(accum, { value, suffix }) - elseif t == "table" then + elseif "table" == _exp_0 then extract_assign_names(value, accum, suffix) else user_error("Can't destructure value of type: " .. tostring(ntype(value))) diff --git a/moonscript/transform/destructure.moon b/moonscript/transform/destructure.moon index 7175854f..274e6ed3 100644 --- a/moonscript/transform/destructure.moon +++ b/moonscript/transform/destructure.moon @@ -43,13 +43,13 @@ extract_assign_names = (name, accum={}, prefix={}) -> suffix = join prefix, {suffix} - t = ntype value - if t == "value" or t == "chain" or t == "self" - insert accum, {value, suffix} - elseif t == "table" - extract_assign_names value, accum, suffix - else - user_error "Can't destructure value of type: #{ntype value}" + switch ntype value + when "value", "ref", "chain", "self" + insert accum, {value, suffix} + when "table" + extract_assign_names value, accum, suffix + else + user_error "Can't destructure value of type: #{ntype value}" accum From d6eaf8ddfb114b444ebae1a379c304a383c579e1 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 27 Dec 2013 02:15:51 -0800 Subject: [PATCH 164/554] finish integrating ref value type --- moonscript/compile.lua | 8 ++++++-- moonscript/compile.moon | 12 +++++++++--- moonscript/compile/value.lua | 28 +++++++++++++++++----------- moonscript/compile/value.moon | 22 +++++++++++----------- moonscript/parse.lua | 18 +++++++++--------- moonscript/transform.lua | 23 +++++++++++++++++------ moonscript/transform.moon | 26 ++++++++++++++++++++------ 7 files changed, 89 insertions(+), 48 deletions(-) diff --git a/moonscript/compile.lua b/moonscript/compile.lua index 0970eab3..1fd67abd 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -321,6 +321,8 @@ do real_name = name:get_name(self) elseif NameProxy == _exp_0 then real_name = name:get_name(self) + elseif "table" == _exp_0 then + real_name = name[1] == "ref" and name[2] elseif "string" == _exp_0 then real_name = name end @@ -388,8 +390,10 @@ do if t == NameProxy or t == LocalName then return true end - if t == "table" and node[1] == "chain" and #node == 2 then - return self:is_local(node[2]) + if t == "table" then + if node[1] == "ref" or (node[1] == "chain" and #node == 2) then + return self:is_local(node[2]) + end end return false end, diff --git a/moonscript/compile.moon b/moonscript/compile.moon index 33bb719a..67e74aff 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -219,7 +219,11 @@ class Block is_local = true name\get_name self when NameProxy then name\get_name self - when "string" then name + when "table" + name[1] == "ref" and name[2] + when "string" + -- TODO: don't use string literal as ref + name continue unless is_local or real_name and not @has_name real_name, true -- put exported names so they can be assigned to in deeper scope @@ -257,11 +261,13 @@ class Block is_local: (node) => t = mtype node + return @has_name(node, false) if t == "string" return true if t == NameProxy or t == LocalName - if t == "table" and node[1] == "chain" and #node == 2 - return @is_local node[2] + if t == "table" + if node[1] == "ref" or (node[1] == "chain" and #node == 2) + return @is_local node[2] false diff --git a/moonscript/compile/value.lua b/moonscript/compile/value.lua index 99b1b15a..46e3832b 100644 --- a/moonscript/compile/value.lua +++ b/moonscript/compile/value.lua @@ -76,15 +76,20 @@ local value_compilers = { end, chain = function(self, node) local callee = node[2] + local callee_type = ntype(callee) if callee == -1 then callee = self:get("scope_var") if not callee then user_error("Short-dot syntax must be called within a with block") end end - local sup = self:get("super") - if callee == "super" and sup then - return self:value(sup(self, node)) + if callee_type == "ref" and callee[2] == "super" or callee == "super" then + do + local sup = self:get("super") + if sup then + return self:value(sup(self, node)) + end + end end local chain_item chain_item = function(node) @@ -100,12 +105,11 @@ local value_compilers = { elseif t == "colon_stub" then return user_error("Uncalled colon stub") else - return error("Unknown chain action: " .. t) + return error("Unknown chain action: " .. tostring(t)) end end - local t = ntype(callee) - if (t == "self" or t == "self_class") and node[3] and ntype(node[3]) == "call" then - callee[1] = t .. "_colon" + if (callee_type == "self" or callee_type == "self_class") and node[3] and ntype(node[3]) == "call" then + callee[1] = callee_type .. "_colon" end local callee_value = self:value(callee) if ntype(callee) == "exp" then @@ -294,13 +298,15 @@ local value_compilers = { return "self.__class:" .. self:value(node[2]) end, ref = function(self, value) + do + local sup = value[2] == "super" and self:get("super") + if sup then + return self:value(sup(self)) + end + end return tostring(value[2]) end, raw_value = function(self, value) - local sup = self:get("super") - if value == "super" and sup then - return self:value(sup(self)) - end if value == "..." then self:send("varargs") end diff --git a/moonscript/compile/value.moon b/moonscript/compile/value.moon index 77e87c82..4d4fe0e4 100644 --- a/moonscript/compile/value.moon +++ b/moonscript/compile/value.moon @@ -43,14 +43,16 @@ value_compilers = chain: (node) => callee = node[2] + callee_type = ntype callee if callee == -1 callee = @get "scope_var" if not callee then user_error "Short-dot syntax must be called within a with block" - sup = @get "super" - if callee == "super" and sup - return @value sup self, node + -- TODO: don't use string literals as ref + if callee_type == "ref" and callee[2] == "super" or callee == "super" + if sup = @get "super" + return @value sup self, node chain_item = (node) -> t, arg = unpack node @@ -66,11 +68,10 @@ value_compilers = elseif t == "colon_stub" user_error "Uncalled colon stub" else - error "Unknown chain action: "..t + error "Unknown chain action: #{t}" - t = ntype(callee) - if (t == "self" or t == "self_class") and node[3] and ntype(node[3]) == "call" - callee[1] = t.."_colon" + if (callee_type == "self" or callee_type == "self_class") and node[3] and ntype(node[3]) == "call" + callee[1] = callee_type.."_colon" callee_value = @value callee callee_value = @line "(", callee_value, ")" if ntype(callee) == "exp" @@ -185,14 +186,13 @@ value_compilers = -- a variable reference ref: (value) => + if sup = value[2] == "super" and @get "super" + return @value sup @ + tostring value[2] -- catch all pure string values raw_value: (value) => - sup = @get"super" - if value == "super" and sup - return @value sup self - if value == "..." @send "varargs" diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 34c1871c..0a28f58b 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -174,6 +174,10 @@ end local _chain_assignable = { index = true, dot = true, slice = true } local function is_assignable(node) + if node == "..." then + return false + end + local t = ntype(node) return t == "ref" or t == "self" or t == "value" or t == "self_class" or t == "chain" and _chain_assignable[ntype(node[#node])] or @@ -378,8 +382,7 @@ local build_grammar = wrap_env(function() _Name / mark"self" + Cc"self") local KeyName = SelfName + Space * _Name / mark"key_literal" - - local Name = SelfName + Name + Space * "..." / trim + local VarArg = Space * P"..." / trim local g = lpeg.P{ File, @@ -413,8 +416,6 @@ local build_grammar = wrap_env(function() ImportName = (sym"\\" * Ct(Cc"colon_stub" * Name) + Name), ImportNameList = SpaceBreak^0 * ImportName * ((SpaceBreak^1 + sym"," * SpaceBreak^0) * ImportName)^0, - NameList = Name * (sym"," * Name)^0, - BreakLoop = Ct(key"break"/trim) + Ct(key"continue"/trim), Return = key"return" * (ExpListLow/mark"explist" + C"") / mark"return", @@ -461,8 +462,7 @@ local build_grammar = wrap_env(function() -- we can ignore precedence for now OtherOps = op"or" + op"and" + op"<=" + op">=" + op"~=" + op"!=" + op"==" + op".." + op"<" + op">", - Assignable = Cmt(DotChain + Chain, check_assignable) + Name, - AssignableList = Assignable * (sym"," * Assignable)^0, + Assignable = Cmt(DotChain + Chain, check_assignable) + Name + SelfName, Exp = Ct(Value * ((OtherOps + FactorOp + TermOp) * Value)^0) / flatten_or_mark"exp", @@ -511,7 +511,7 @@ local build_grammar = wrap_env(function() LuaStringOpen = sym"[" * P"="^0 * "[" / trim, LuaStringClose = "]" * P"="^0 * "]", - Callable = Name / mark"ref" + Parens / mark"parens", + Callable = Name / mark"ref" + SelfName + VarArg + Parens / mark"parens", Parens = sym"(" * Exp * sym")", FnArgs = symx"(" * Ct(ExpList^-1) * sym")" + sym"!" * -P"=" * Ct"", @@ -583,8 +583,8 @@ local build_grammar = wrap_env(function() (key"using" * Ct(NameList + Space * "nil") + Ct"") * sym")" + Ct"" * Ct"", - FnArgDefList = FnArgDef * (sym"," * FnArgDef)^0, - FnArgDef = Ct(Name * (sym"=" * Exp)^-1), + FnArgDefList = FnArgDef * (sym"," * FnArgDef)^0 * (sym"," * Ct(VarArg))^0 + Ct(VarArg), + FnArgDef = Ct((Name + SelfName) * (sym"=" * Exp)^-1), FunLit = FnArgsDef * (sym"->" * Cc"slim" + sym"=>" * Cc"fat") * diff --git a/moonscript/transform.lua b/moonscript/transform.lua index bd30f770..73deb86f 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -107,7 +107,9 @@ extract_declarations = function(self, body, start, out) local _list_0 = stm[2] for _index_0 = 1, #_list_0 do local name = _list_0[_index_0] - if type(name) == "string" then + if ntype(name) == "ref" then + insert(out, name) + elseif type(name) == "string" then insert(out, name) end end @@ -348,7 +350,7 @@ Statement = Transformer({ local _continue_0 = false repeat local name = names[_index_0] - if not (name:match("^%u")) then + if not (name[2]:match("^%u")) then _continue_0 = true break end @@ -599,7 +601,7 @@ Statement = Transformer({ local _list_0 = stm[2] for _index_0 = 1, #_list_0 do local name = _list_0[_index_0] - if type(name) == "string" then + if ntype(name) == "ref" then _accum_0[_len_0] = name _len_0 = _len_0 + 1 end @@ -674,7 +676,7 @@ Statement = Transformer({ if ntype(exp) == "assign" then local names, values = unpack(exp, 2) local first_name = names[1] - if ntype(first_name) == "value" then + if ntype(first_name) == "ref" then scope_name = first_name named_assign = exp exp = values[1] @@ -966,10 +968,19 @@ Statement = Transformer({ elseif "nil" == _exp_0 then real_name = "nil" else + local name_t = type(real_name) + local flattened_name + if name_t == "string" then + flattened_name = real_name + elseif name_t == "table" and real_name[1] == "ref" then + flattened_name = real_name[2] + else + flattened_name = error("don't know how to extract name from " .. tostring(name_t)) + end real_name = { "string", '"', - real_name + flattened_name } end local cls = build.table({ @@ -1520,7 +1531,7 @@ Value = Transformer({ table.remove(node, #node) local base_name = NameProxy("base") local fn_name = NameProxy("fn") - local is_super = node[2] == "super" + local is_super = ntype(node[2]) == "ref" and node[2][2] == "super" return self.transform.value(build.block_exp({ build.assign({ names = { diff --git a/moonscript/transform.moon b/moonscript/transform.moon index a1b0a9f7..8cde3102 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -55,7 +55,11 @@ extract_declarations = (body=@current_stms, start=@current_stm_i + 1, out={}) => switch stm[1] when "assign", "declare" for name in *stm[2] - insert out, name if type(name) == "string" + if ntype(name) == "ref" + insert out, name + elseif type(name) == "string" + -- TODO: don't use string literal as ref + insert out, name when "group" extract_declarations @, stm[2], 1, out out @@ -187,7 +191,7 @@ Statement = Transformer { if node[2] == "^" names = for name in *names - continue unless name\match "^%u" + continue unless name[2]\match "^%u" name {"declare", names} @@ -321,7 +325,7 @@ Statement = Transformer { if ntype(stm) == "assign" wrapped = build.group { - build.declare names: [name for name in *stm[2] when type(name) == "string"] + build.declare names: [name for name in *stm[2] when ntype(name) == "ref"] wrapped } @@ -373,11 +377,12 @@ Statement = Transformer { copy_scope = true local scope_name, named_assign + if ntype(exp) == "assign" names, values = unpack exp, 2 first_name = names[1] - if ntype(first_name) == "value" + if ntype(first_name) == "ref" scope_name = first_name named_assign = exp exp = values[1] @@ -577,7 +582,16 @@ Statement = Transformer { when "nil" "nil" else - {"string", '"', real_name} + name_t = type real_name + -- TODO: don't use string literal as ref + flattened_name = if name_t == "string" + real_name + elseif name_t == "table" and real_name[1] == "ref" + real_name[2] + else + error "don't know how to extract name from #{name_t}" + + {"string", '"', flattened_name} cls = build.table { {"__init", constructor} @@ -907,7 +921,7 @@ Value = Transformer { base_name = NameProxy "base" fn_name = NameProxy "fn" - is_super = node[2] == "super" + is_super = ntype(node[2]) == "ref" and node[2][2] == "super" @transform.value build.block_exp { build.assign { names: {base_name} From 887745491d56d4466dd4e72770d972186fb852de Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 27 Dec 2013 03:51:59 -0800 Subject: [PATCH 165/554] use ref correctly in generated code, don't pass basic names to value --- moonscript/compile.lua | 6 +++++- moonscript/compile.moon | 8 ++++++-- moonscript/compile/value.lua | 13 ++++++++----- moonscript/compile/value.moon | 11 +++++------ moonscript/transform.lua | 10 ++++++++-- moonscript/transform.moon | 4 ++-- moonscript/transform/names.lua | 6 ++++++ moonscript/transform/names.moon | 3 +++ moonscript/types.lua | 6 ++++++ moonscript/types.moon | 5 +++++ 10 files changed, 54 insertions(+), 18 deletions(-) diff --git a/moonscript/compile.lua b/moonscript/compile.lua index 1fd67abd..2b8e1630 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -467,7 +467,11 @@ do return self.value_compilers[t] ~= nil or t == "value" end, name = function(self, node, ...) - return self:value(node, ...) + if type(node) == "string" then + return node + else + return self:value(node, ...) + end end, value = function(self, node, ...) node = self.transform.value(node) diff --git a/moonscript/compile.moon b/moonscript/compile.moon index 67e74aff..812ad74e 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -326,8 +326,12 @@ class Block t = ntype node @value_compilers[t] != nil or t == "value" - -- line wise compile functions - name: (node, ...) => @value node, ... + -- compile name for assign + name: (node, ...) => + if type(node) == "string" + node + else + @value node, ... value: (node, ...) => node = @transform.value node diff --git a/moonscript/compile/value.lua b/moonscript/compile/value.lua index 46e3832b..0a9acd80 100644 --- a/moonscript/compile/value.lua +++ b/moonscript/compile/value.lua @@ -176,7 +176,10 @@ local value_compilers = { 'if', { 'exp', - name, + { + "ref", + name + }, '==', 'nil' }, @@ -286,16 +289,16 @@ local value_compilers = { return self:line("not ", self:value(node[2])) end, self = function(self, node) - return "self." .. self:value(node[2]) + return "self." .. self:name(node[2]) end, self_class = function(self, node) - return "self.__class." .. self:value(node[2]) + return "self.__class." .. self:name(node[2]) end, self_colon = function(self, node) - return "self:" .. self:value(node[2]) + return "self:" .. self:name(node[2]) end, self_class_colon = function(self, node) - return "self.__class:" .. self:value(node[2]) + return "self.__class:" .. self:name(node[2]) end, ref = function(self, value) do diff --git a/moonscript/compile/value.moon b/moonscript/compile/value.moon index 4d4fe0e4..27aa9f2f 100644 --- a/moonscript/compile/value.moon +++ b/moonscript/compile/value.moon @@ -110,7 +110,7 @@ value_compilers = name, value = unpack default name = name[2] if type(name) == "table" \stm { - 'if', {'exp', name, '==', 'nil'}, { + 'if', {'exp', {"ref", name}, '==', 'nil'}, { {'assign', {name}, {value}} } } @@ -173,16 +173,16 @@ value_compilers = @line "not ", @value node[2] self: (node) => - "self."..@value node[2] + "self."..@name node[2] self_class: (node) => - "self.__class."..@value node[2] + "self.__class."..@name node[2] self_colon: (node) => - "self:"..@value node[2] + "self:"..@name node[2] self_class_colon: (node) => - "self.__class:"..@value node[2] + "self.__class:"..@name node[2] -- a variable reference ref: (value) => @@ -198,5 +198,4 @@ value_compilers = tostring value - { :value_compilers } diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 73deb86f..449e983a 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -1006,7 +1006,10 @@ Statement = Transformer({ local class_lookup = build["if"]({ cond = { "exp", - "val", + { + "ref", + "val" + }, "==", "nil" }, @@ -1036,7 +1039,10 @@ Statement = Transformer({ "call", { base_name, - "name" + { + "ref", + "name" + } } } })), diff --git a/moonscript/transform.moon b/moonscript/transform.moon index 8cde3102..9175d417 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -603,7 +603,7 @@ Statement = Transformer { -- looking up a name in the class object class_index = if parent_val class_lookup = build["if"] { - cond: { "exp", "val", "==", "nil" } + cond: { "exp", {"ref", "val"}, "==", "nil" } then: { parent_cls_name\index"name" } @@ -614,7 +614,7 @@ Statement = Transformer { args: {{"cls"}, {"name"}} body: { build.assign_one LocalName"val", build.chain { - base: "rawget", {"call", {base_name, "name"}} + base: "rawget", {"call", {base_name, {"ref", "name"}}} } class_lookup } diff --git a/moonscript/transform/names.lua b/moonscript/transform/names.lua index 987d71cd..abc0d5b9 100644 --- a/moonscript/transform/names.lua +++ b/moonscript/transform/names.lua @@ -74,6 +74,12 @@ do }) end, index = function(self, key) + if type(key) == "string" then + key = { + "ref", + key + } + end return build.chain({ base = self, { diff --git a/moonscript/transform/names.moon b/moonscript/transform/names.moon index 24fc126b..daf17ed9 100644 --- a/moonscript/transform/names.moon +++ b/moonscript/transform/names.moon @@ -30,6 +30,9 @@ class NameProxy } index: (key) => + if type(key) == "string" + key = {"ref", key} + build.chain { base: self, {"index", key} } diff --git a/moonscript/types.lua b/moonscript/types.lua index b9087f6f..aae50c91 100644 --- a/moonscript/types.lua +++ b/moonscript/types.lua @@ -263,6 +263,12 @@ build = setmetatable({ end, chain = function(parts) local base = parts.base or error("expecting base property for chain") + if type(base) == "string" then + base = { + "ref", + base + } + end local node = { "chain", base diff --git a/moonscript/types.moon b/moonscript/types.moon index aee741ad..9b415231 100644 --- a/moonscript/types.moon +++ b/moonscript/types.moon @@ -141,8 +141,13 @@ build = setmetatable { {"table", tbl} block_exp: (body) -> {"block_exp", body} + chain: (parts) -> base = parts.base or error"expecting base property for chain" + + if type(base) == "string" + base = {"ref", base} + node = {"chain", base} for part in *parts insert node, part From da0109bd14cb5ac084ad8260b8eb835bf7eb310c Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 27 Dec 2013 04:00:46 -0800 Subject: [PATCH 166/554] make lint use ref, whitelist nil, true, false --- moonscript/cmd/lint.lua | 12 ++++++++---- moonscript/cmd/lint.moon | 12 ++++++++---- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/moonscript/cmd/lint.lua b/moonscript/cmd/lint.lua index b47842bf..291cf71f 100644 --- a/moonscript/cmd/lint.lua +++ b/moonscript/cmd/lint.lua @@ -50,7 +50,10 @@ local whitelist_globals = Set({ 'setmetatable', 'tonumber', 'collectgarbage', - 'coroutine' + 'coroutine', + "nil", + "true", + "false" }) local LinterBlock do @@ -75,15 +78,16 @@ do _parent_0.__init(self, ...) local vc = self.value_compilers self.value_compilers = setmetatable({ - raw_value = function(block, name) - if name:match("^[%w_]+$") and not block:has_name(name) and not whitelist_globals[name] then + ref = function(block, val) + local name = val[2] + if not (block:has_name(name) or whitelist_globals[name]) then local stm = block.current_stms[block.current_stm_i] insert(self.lint_errors, { "accessing global " .. tostring(name), stm[-1] }) end - return vc.raw_value(block, name) + return vc.raw_value(block, val) end }, { __index = vc diff --git a/moonscript/cmd/lint.moon b/moonscript/cmd/lint.moon index b0fcd58e..236a4748 100644 --- a/moonscript/cmd/lint.moon +++ b/moonscript/cmd/lint.moon @@ -42,6 +42,10 @@ whitelist_globals = Set { 'tonumber' 'collectgarbage' 'coroutine' + + "nil" + "true" + "false" } class LinterBlock extends Block @@ -50,16 +54,16 @@ class LinterBlock extends Block vc = @value_compilers @value_compilers = setmetatable { - raw_value: (block, name) -> - - if name\match("^[%w_]+$") and not block\has_name(name) and not whitelist_globals[name] + ref: (block, val) -> + name = val[2] + unless block\has_name(name) or whitelist_globals[name] stm = block.current_stms[block.current_stm_i] insert @lint_errors, { "accessing global #{name}" stm[-1] } - vc.raw_value block, name + vc.raw_value block, val }, __index: vc block: (...) => From 53cf5dd649312ebd99c521796715b6015f53a2ff Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 27 Dec 2013 12:57:07 -0800 Subject: [PATCH 167/554] fix lint, mark pos of all refs --- moonscript/cmd/lint.lua | 8 ++++---- moonscript/cmd/lint.moon | 8 ++++---- moonscript/parse.lua | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/moonscript/cmd/lint.lua b/moonscript/cmd/lint.lua index 291cf71f..5b0bfd17 100644 --- a/moonscript/cmd/lint.lua +++ b/moonscript/cmd/lint.lua @@ -62,6 +62,7 @@ do block = function(self, ...) do local _with_0 = _parent_0.block(self, ...) + _with_0.block = self.block _with_0.value_compilers = self.value_compilers return _with_0 end @@ -80,14 +81,13 @@ do self.value_compilers = setmetatable({ ref = function(block, val) local name = val[2] - if not (block:has_name(name) or whitelist_globals[name]) then - local stm = block.current_stms[block.current_stm_i] + if not (block:has_name(name) or whitelist_globals[name] or name:match("%.")) then insert(self.lint_errors, { "accessing global " .. tostring(name), - stm[-1] + val[-1] }) end - return vc.raw_value(block, val) + return vc.ref(block, val) end }, { __index = vc diff --git a/moonscript/cmd/lint.moon b/moonscript/cmd/lint.moon index 236a4748..9d883d39 100644 --- a/moonscript/cmd/lint.moon +++ b/moonscript/cmd/lint.moon @@ -56,18 +56,18 @@ class LinterBlock extends Block @value_compilers = setmetatable { ref: (block, val) -> name = val[2] - unless block\has_name(name) or whitelist_globals[name] - stm = block.current_stms[block.current_stm_i] + unless block\has_name(name) or whitelist_globals[name] or name\match "%." insert @lint_errors, { "accessing global #{name}" - stm[-1] + val[-1] } - vc.raw_value block, val + vc.ref block, val }, __index: vc block: (...) => with super ... + .block = @block .value_compilers = @value_compilers format_lint = (errors, code, header) -> diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 0a28f58b..499ae1b7 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -511,7 +511,7 @@ local build_grammar = wrap_env(function() LuaStringOpen = sym"[" * P"="^0 * "[" / trim, LuaStringClose = "]" * P"="^0 * "]", - Callable = Name / mark"ref" + SelfName + VarArg + Parens / mark"parens", + Callable = pos(Name / mark"ref") + SelfName + VarArg + Parens / mark"parens", Parens = sym"(" * Exp * sym")", FnArgs = symx"(" * Ct(ExpList^-1) * sym")" + sym"!" * -P"=" * Ct"", From db439f880a35bba0c3403a29f854cdc8d9918b1a Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 27 Dec 2013 15:30:21 -0800 Subject: [PATCH 168/554] load a lint config --- moonscript/cmd/lint.lua | 43 ++++++++++++++++++++++++++++++++-------- moonscript/cmd/lint.moon | 34 ++++++++++++++++++++++++++----- 2 files changed, 64 insertions(+), 13 deletions(-) diff --git a/moonscript/cmd/lint.lua b/moonscript/cmd/lint.lua index 5b0bfd17..9dbbcc53 100644 --- a/moonscript/cmd/lint.lua +++ b/moonscript/cmd/lint.lua @@ -13,7 +13,7 @@ do local _obj_0 = require("moonscript.compile") Block = _obj_0.Block end -local whitelist_globals = Set({ +local default_whitelist = Set({ 'loadstring', 'select', '_VERSION', @@ -71,12 +71,12 @@ do _base_0.__index = _base_0 setmetatable(_base_0, _parent_0.__base) local _class_0 = setmetatable({ - __init = function(self, lint_errors, ...) - if lint_errors == nil then - lint_errors = { } + __init = function(self, whitelist_globals, ...) + if whitelist_globals == nil then + whitelist_globals = default_whitelist end - self.lint_errors = lint_errors _parent_0.__init(self, ...) + self.lint_errors = { } local vc = self.value_compilers self.value_compilers = setmetatable({ ref = function(block, val) @@ -157,8 +157,35 @@ format_lint = function(errors, code, header) end return table.concat(formatted, "\n\n") end +local whitelist_for_file +do + local lint_config + whitelist_for_file = function(fname) + if not (lint_config) then + lint_config = { } + pcall(function() + lint_config = require("lint_config") + end) + end + if not (lint_config.whitelist_globals) then + return default_whitelist + end + local final_list = { } + for pattern, list in pairs(lint_config.whitelist_globals) do + if fname:match(pattern) then + for _index_0 = 1, #list do + local item = list[_index_0] + insert(final_list, item) + end + end + end + return setmetatable(Set(final_list), { + __index = default_whitelist + }) + end +end local lint_code -lint_code = function(code, name) +lint_code = function(code, name, whitelist_globals) if name == nil then name = "string input" end @@ -167,7 +194,7 @@ lint_code = function(code, name) if not (tree) then return nil, err end - local scope = LinterBlock() + local scope = LinterBlock(whitelist_globals) scope:stms(tree) return format_lint(scope.lint_errors, code, name) end @@ -177,7 +204,7 @@ lint_file = function(fname) if not (f) then return nil, err end - return lint_code(f:read("*a"), fname) + return lint_code(f:read("*a"), fname, whitelist_for_file(fname)) end return { lint_code = lint_code, diff --git a/moonscript/cmd/lint.moon b/moonscript/cmd/lint.moon index 9d883d39..93730bcd 100644 --- a/moonscript/cmd/lint.moon +++ b/moonscript/cmd/lint.moon @@ -4,7 +4,7 @@ import Set from require "moonscript.data" import Block from require "moonscript.compile" -- globals allowed to be referenced -whitelist_globals = Set { +default_whitelist = Set { 'loadstring' 'select' '_VERSION' @@ -49,8 +49,9 @@ whitelist_globals = Set { } class LinterBlock extends Block - new: (@lint_errors={}, ...) => + new: (whitelist_globals=default_whitelist, ...) => super ... + @lint_errors = {} vc = @value_compilers @value_compilers = setmetatable { @@ -94,19 +95,42 @@ format_lint = (errors, code, header) -> table.concat formatted, "\n\n" -lint_code = (code, name="string input") -> +-- { +-- whitelist_globals: { +-- ["some_file_pattern"]: { +-- "some_var", "another_var" +-- } +-- } +-- } +whitelist_for_file = do + local lint_config + (fname) -> + unless lint_config + lint_config = {} + pcall -> lint_config = require "lint_config" + + return default_whitelist unless lint_config.whitelist_globals + final_list = {} + for pattern, list in pairs lint_config.whitelist_globals + if fname\match(pattern) + for item in *list + insert final_list, item + + setmetatable Set(final_list), __index: default_whitelist + +lint_code = (code, name="string input", whitelist_globals) -> parse = require "moonscript.parse" tree, err = parse.string code return nil, err unless tree - scope = LinterBlock! + scope = LinterBlock whitelist_globals scope\stms tree format_lint scope.lint_errors, code, name lint_file = (fname) -> f, err = io.open fname return nil, err unless f - lint_code f\read("*a"), fname + lint_code f\read("*a"), fname, whitelist_for_file fname { :lint_code, :lint_file } From 49b1c6e8a34650a5e0dbd33fccf8a3061da755de Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 27 Dec 2013 15:32:06 -0800 Subject: [PATCH 169/554] show failed files when linting --- bin/moonc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bin/moonc b/bin/moonc index 7ce00f37..7c6f1f34 100755 --- a/bin/moonc +++ b/bin/moonc @@ -390,9 +390,11 @@ if opts.w then elseif opts.l then for _, fname in pairs(files) do lint = require "moonscript.cmd.lint" - local res = lint.lint_file(fname) + local res, err = lint.lint_file(fname) if res then io.stderr:write(res .. "\n\n") + elseif err then + io.stderr:write(fname .. "\n" .. err.. "\n\n") end end else From ca4427cf6d5cca874746f95dbbef898970730685 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 27 Dec 2013 15:57:01 -0800 Subject: [PATCH 170/554] add missing functions to default whitelist, sort it --- moonscript/cmd/lint.lua | 58 +++++++++++++++++++++------------------- moonscript/cmd/lint.moon | 58 +++++++++++++++++++++------------------- 2 files changed, 60 insertions(+), 56 deletions(-) diff --git a/moonscript/cmd/lint.lua b/moonscript/cmd/lint.lua index 9dbbcc53..a8c08903 100644 --- a/moonscript/cmd/lint.lua +++ b/moonscript/cmd/lint.lua @@ -14,43 +14,45 @@ do Block = _obj_0.Block end local default_whitelist = Set({ - 'loadstring', - 'select', + '_G', '_VERSION', - 'pcall', - 'package', + 'assert', + 'bit32', + 'collectgarbage', + 'coroutine', + 'debug', + 'dofile', 'error', - 'rawget', - 'pairs', - 'xpcall', - 'rawlen', + 'getfenv', + 'getmetatable', 'io', - 'loadfile', 'ipairs', - 'table', - 'require', - 'os', + 'load', + 'loadfile', + 'loadstring', + 'math', 'module', - 'debug', - 'type', - 'getmetatable', + 'next', + 'os', + 'package', + 'pairs', + 'pcall', + 'print', 'rawequal', - 'dofile', - 'unpack', - 'math', - 'load', - 'bit32', - 'string', + 'rawget', + 'rawlen', 'rawset', - 'tostring', - 'print', - 'assert', - '_G', - 'next', + 'require', + 'select', + 'setfenv', 'setmetatable', + 'string', + 'table', 'tonumber', - 'collectgarbage', - 'coroutine', + 'tostring', + 'type', + 'unpack', + 'xpcall', "nil", "true", "false" diff --git a/moonscript/cmd/lint.moon b/moonscript/cmd/lint.moon index 93730bcd..4add665b 100644 --- a/moonscript/cmd/lint.moon +++ b/moonscript/cmd/lint.moon @@ -5,43 +5,45 @@ import Block from require "moonscript.compile" -- globals allowed to be referenced default_whitelist = Set { - 'loadstring' - 'select' + '_G' '_VERSION' - 'pcall' - 'package' + 'assert' + 'bit32' + 'collectgarbage' + 'coroutine' + 'debug' + 'dofile' 'error' - 'rawget' - 'pairs' - 'xpcall' - 'rawlen' + 'getfenv' + 'getmetatable' 'io' - 'loadfile' 'ipairs' - 'table' - 'require' - 'os' + 'load' + 'loadfile' + 'loadstring' + 'math' 'module' - 'debug' - 'type' - 'getmetatable' + 'next' + 'os' + 'package' + 'pairs' + 'pcall' + 'print' 'rawequal' - 'dofile' - 'unpack' - 'math' - 'load' - 'bit32' - 'string' + 'rawget' + 'rawlen' 'rawset' - 'tostring' - 'print' - 'assert' - '_G' - 'next' + 'require' + 'select' + 'setfenv' 'setmetatable' + 'string' + 'table' 'tonumber' - 'collectgarbage' - 'coroutine' + 'tostring' + 'type' + 'unpack' + 'xpcall' "nil" "true" From dd1a06ff1a0018cabf8e520ed259a405218cb17b Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Mon, 30 Dec 2013 01:38:22 -0800 Subject: [PATCH 171/554] update thoughts --- thoughts | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/thoughts b/thoughts index 735f6684..dfd6b69d 100644 --- a/thoughts +++ b/thoughts @@ -3,16 +3,10 @@ # # --- local * and local ^ - --- seems like running in moon messes up require order - - don't reuse _, put a local on it, so we don't keep around trash -- swithc X with Func -- or= and= - - error with stray comma at end of line * multiline comments @@ -20,22 +14,18 @@ * combine for and if line decorators -* export later? nah - - x = 232 - export x - - * allow return anywhere in block -* any/every keywords for comprehensions? (what about iterators) +-- all function literals have a string that is their function definition -* let array items in table be defined without {} when indented (no, too similar to arguments) +-- super should work here: --- for searching? for returning to accumulator early? -x = for thing in *things - if is_important thing - break thing +thing = Thing! +thing.method = -> + super 1,2,3 --- all function literals have a string that is their function definition +-- goes to +thing.method = function(self) do + self.__class:method(1,2,3) +end From 23a99aa365f2f81ec42a994f85c1708a87dc4a91 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Mon, 30 Dec 2013 01:43:25 -0800 Subject: [PATCH 172/554] cleaning up --- moonscript/data.lua | 24 +++++++++++------------- moonscript/data.moon | 20 ++++++++++---------- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/moonscript/data.lua b/moonscript/data.lua index 69176969..2e159c83 100644 --- a/moonscript/data.lua +++ b/moonscript/data.lua @@ -5,12 +5,12 @@ do end local Set Set = function(items) - local self = { } + local _tbl_0 = { } for _index_0 = 1, #items do - local key = items[_index_0] - self[key] = true + local k = items[_index_0] + _tbl_0[k] = true end - return self + return _tbl_0 end local Stack do @@ -21,9 +21,13 @@ do pop = function(self) return remove(self) end, - push = function(self, value) + push = function(self, value, ...) insert(self, value) - return value + if ... then + return self:push(...) + else + return value + end end, top = function(self) return self[#self] @@ -32,13 +36,7 @@ do _base_0.__index = _base_0 local _class_0 = setmetatable({ __init = function(self, ...) - local _list_0 = { - ... - } - for _index_0 = 1, #_list_0 do - local v = _list_0[_index_0] - self:push(v) - end + self:push(...) return nil end, __base = _base_0, diff --git a/moonscript/data.moon b/moonscript/data.moon index a9fbf328..4bb9b4fb 100644 --- a/moonscript/data.moon +++ b/moonscript/data.moon @@ -2,30 +2,30 @@ import concat, remove, insert from table -Set = (items) -> - self = {} - self[key] = true for key in *items - self +Set = (items) -> {k,true for k in *items} class Stack __tostring: => "" new: (...) => - @push v for v in *{...} + @push ... nil pop: => - remove self + remove @ - push: (value) => - insert self, value - value + push: (value, ...) => + insert @, value + if ... + @push ... + else + value top: => self[#self] -lua_keywords = Set{ +lua_keywords = Set { 'and', 'break', 'do', 'else', 'elseif', 'end', 'false', 'for', 'function', 'if', 'in', 'local', 'nil', 'not', 'or', From 5d9ee66c147662d6ab5ca7e1001b7edf48ce6319 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Mon, 30 Dec 2013 01:45:59 -0800 Subject: [PATCH 173/554] remove extra tables --- moonscript/compile.lua | 12 ++---------- moonscript/compile.moon | 4 ++-- moonscript/compile/statement.lua | 5 +---- moonscript/compile/statement.moon | 6 ++---- moonscript/compile/value.lua | 5 +---- moonscript/compile/value.moon | 5 ++--- 6 files changed, 10 insertions(+), 27 deletions(-) diff --git a/moonscript/compile.lua b/moonscript/compile.lua index 2b8e1630..368eead7 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -16,16 +16,8 @@ do local _obj_0 = require("moonscript.types") ntype, has_value = _obj_0.ntype, _obj_0.has_value end -local statement_compilers -do - local _obj_0 = require("moonscript.compile.statement") - statement_compilers = _obj_0.statement_compilers -end -local value_compilers -do - local _obj_0 = require("moonscript.compile.value") - value_compilers = _obj_0.value_compilers -end +local statement_compilers = require("moonscript.compile.statement") +local value_compilers = require("moonscript.compile.value") local concat, insert do local _obj_0 = table diff --git a/moonscript/compile.moon b/moonscript/compile.moon index 812ad74e..27ab017c 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -7,8 +7,8 @@ import NameProxy, LocalName from require "moonscript.transform.names" import Set from require "moonscript.data" import ntype, has_value from require "moonscript.types" -import statement_compilers from require "moonscript.compile.statement" -import value_compilers from require "moonscript.compile.value" +statement_compilers = require "moonscript.compile.statement" +value_compilers = require "moonscript.compile.value" import concat, insert from table import pos_to_line, get_closest_line, trim, unpack from util diff --git a/moonscript/compile/statement.lua b/moonscript/compile/statement.lua index 65cc2d5e..abccd627 100644 --- a/moonscript/compile/statement.lua +++ b/moonscript/compile/statement.lua @@ -12,7 +12,7 @@ do local _obj_0 = table concat, insert = _obj_0.concat, _obj_0.insert end -local statement_compilers = { +return { raw = function(self, node) return self:add(node[2]) end, @@ -243,6 +243,3 @@ local statement_compilers = { end, noop = function(self) end } -return { - statement_compilers = statement_compilers -} diff --git a/moonscript/compile/statement.moon b/moonscript/compile/statement.moon index cf89e144..996b3855 100644 --- a/moonscript/compile/statement.moon +++ b/moonscript/compile/statement.moon @@ -6,7 +6,7 @@ import reversed, unpack from util import ntype from require "moonscript.types" import concat, insert from table -statement_compilers = +{ raw: (node) => @add node[2] lines: (node) => @@ -136,6 +136,4 @@ statement_compilers = \stms node[2] noop: => -- nothing! - - -{ :statement_compilers } +} diff --git a/moonscript/compile/value.lua b/moonscript/compile/value.lua index 0a9acd80..560352ba 100644 --- a/moonscript/compile/value.lua +++ b/moonscript/compile/value.lua @@ -22,7 +22,7 @@ local string_chars = { ["\r"] = "\\r", ["\n"] = "\\n" } -local value_compilers = { +return { exp = function(self, node) local _comp _comp = function(i, value) @@ -316,6 +316,3 @@ local value_compilers = { return tostring(value) end } -return { - value_compilers = value_compilers -} diff --git a/moonscript/compile/value.moon b/moonscript/compile/value.moon index 27aa9f2f..515fed87 100644 --- a/moonscript/compile/value.moon +++ b/moonscript/compile/value.moon @@ -14,7 +14,7 @@ string_chars = { "\n": "\\n" } -value_compilers = +{ -- list of values separated by binary operators exp: (node) => _comp = (i, value) -> @@ -197,5 +197,4 @@ value_compilers = @send "varargs" tostring value - -{ :value_compilers } +} From 314272c3763e85dd5f4d63b10417708afc280412 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Mon, 30 Dec 2013 01:52:13 -0800 Subject: [PATCH 174/554] don't create unnecessary tables --- moonscript/transform/names.lua | 36 ++++++++++++--------------------- moonscript/transform/names.moon | 14 ++++++------- 2 files changed, 19 insertions(+), 31 deletions(-) diff --git a/moonscript/transform/names.lua b/moonscript/transform/names.lua index abc0d5b9..a7584da1 100644 --- a/moonscript/transform/names.lua +++ b/moonscript/transform/names.lua @@ -47,31 +47,21 @@ do return self.name end, chain = function(self, ...) - local items - do - local _accum_0 = { } - local _len_0 = 1 - local _list_0 = { - ... - } - for _index_0 = 1, #_list_0 do - local i = _list_0[_index_0] - if type(i) == "string" then - _accum_0[_len_0] = { - "dot", - i - } - else - _accum_0[_len_0] = i - end - _len_0 = _len_0 + 1 + local items = { + base = self, + ... + } + for k, v in ipairs(items) do + if type(v) == "string" then + items[k] = { + "dot", + v + } + else + items[k] = v end - items = _accum_0 end - return build.chain({ - base = self, - unpack(items) - }) + return build.chain(items) end, index = function(self, key) if type(key) == "string" then diff --git a/moonscript/transform/names.moon b/moonscript/transform/names.moon index daf17ed9..220d862d 100644 --- a/moonscript/transform/names.moon +++ b/moonscript/transform/names.moon @@ -18,16 +18,14 @@ class NameProxy @name chain: (...) => - items = for i in *{...} - if type(i) == "string" - {"dot", i} + items = { base: @, ... } + for k,v in ipairs items + items[k] = if type(v) == "string" + {"dot", v} else - i + v - build.chain { - base: self - unpack items - } + build.chain items index: (key) => if type(key) == "string" From 9c5940d439fc592cc72af6b07804b106d0ef745b Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 2 Jan 2014 22:27:06 -0800 Subject: [PATCH 175/554] fix typo --- docs/reference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference.md b/docs/reference.md index aab65d09..6af574df 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -644,7 +644,7 @@ have_coins = false if have_coins then print "Got coins" else print "No coins" ``` -Because if statements can be used as expressions, this can able be written as: +Because if statements can be used as expressions, this can also be written as: ```moon have_coins = false From 6aa545e4d325693c09e31f9cd8dfff92af3b5efd Mon Sep 17 00:00:00 2001 From: Lee Miller Date: Fri, 3 Jan 2014 23:27:35 -0800 Subject: [PATCH 176/554] Docs typo fix --- docs/reference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference.md b/docs/reference.md index 6af574df..42992670 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -556,7 +556,7 @@ for item in *items do print item for j = 1,10,3 do print j ``` -A for loop can also be used an expression. The last statement in the body of +A for loop can also be used as an expression. The last statement in the body of the for loop is coerced into an expression and appended to an accumulating array table. From d3f0a455e75dfabe5461cd566b15049063a36820 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 4 Jan 2014 15:41:20 -0800 Subject: [PATCH 177/554] also listen for moved_to --- bin/moonc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/moonc b/bin/moonc index 7c6f1f34..dec5ad7c 100755 --- a/bin/moonc +++ b/bin/moonc @@ -314,7 +314,7 @@ function create_watcher(files) local wd_table = {} local handle = inotify.init() for _, dir in ipairs(dirs) do - local wd = handle:addwatch(dir, inotify.IN_CLOSE_WRITE) + local wd = handle:addwatch(dir, inotify.IN_CLOSE_WRITE, inotify.IN_MOVED_TO) wd_table[wd] = dir end From f49e88b470fa78c45f639aeec1178d2e7291c71e Mon Sep 17 00:00:00 2001 From: Eloff Date: Sun, 5 Jan 2014 01:25:04 -0500 Subject: [PATCH 178/554] Stopped swallowing errors in moonloader. --- moonscript/init.lua | 9 ++++++--- moonscript/init.moon | 10 +++++++--- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/moonscript/init.lua b/moonscript/init.lua index 2488d6d9..deb1a8cc 100644 --- a/moonscript/init.lua +++ b/moonscript/init.lua @@ -56,10 +56,13 @@ moon_loader = function(name) if file then local text = file:read("*a") file:close() - return loadstring(text, file_path) - else - return nil, "Could not find moon file" + local res, err = loadstring(text, file_path) + if not res then + error(err) + end + return res end + return nil, "Could not find moon file" end if not package.moonpath then package.moonpath = create_moonpath(package.path) diff --git a/moonscript/init.moon b/moonscript/init.moon index 2c9fe413..977c63ba 100644 --- a/moonscript/init.moon +++ b/moonscript/init.moon @@ -47,9 +47,13 @@ moon_loader = (name) -> if file text = file\read "*a" file\close! - loadstring text, file_path - else - nil, "Could not find moon file" + res, err = loadstring text, file_path + if not res + error err + + return res + + return nil, "Could not find moon file" if not package.moonpath package.moonpath = create_moonpath package.path From c1f53271143aef88bfcc4ab684f131782a5f5d65 Mon Sep 17 00:00:00 2001 From: Eloff Date: Sun, 5 Jan 2014 15:25:09 -0500 Subject: [PATCH 179/554] Add support for LL and ULL number suffixes (LuaJIT) --- moonscript/parse.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 499ae1b7..eb4bffc4 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -51,7 +51,8 @@ local AlphaNum = R("az", "AZ", "09", "__") local _Name = C(R("az", "AZ", "__") * AlphaNum^0) local Name = Space * _Name -local Num = P"0x" * R("09", "af", "AF")^1 + +local Num = P"0x" * R("09", "af", "AF")^1 * (S"uU"^-1 * S"lL"^2)^-1 + + R"09"^1 * (S"uU"^-1 * S"lL"^2) + ( R"09"^1 * (P"." * R"09"^1)^-1 + P"." * R"09"^1 From a926e968133c96211cf622f0ad173b282e0de216 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Mon, 6 Jan 2014 10:38:01 -0800 Subject: [PATCH 180/554] specs for new number literals #124 --- spec/inputs/literals.moon | 8 ++++++++ spec/outputs/literals.lua | 6 ++++++ 2 files changed, 14 insertions(+) diff --git a/spec/inputs/literals.moon b/spec/inputs/literals.moon index 7f58b6ee..c3a24a6f 100644 --- a/spec/inputs/literals.moon +++ b/spec/inputs/literals.moon @@ -15,6 +15,14 @@ .2323e-1 .2323e13434 + +1LL +1ULL +9332LL +9332 +0x2aLL +0x2aULL + [[ hello world ]] [=[ hello world ]=] diff --git a/spec/outputs/literals.lua b/spec/outputs/literals.lua index b49c57a8..d8fc7e2b 100644 --- a/spec/outputs/literals.lua +++ b/spec/outputs/literals.lua @@ -10,6 +10,12 @@ _ = 0xABCDEF _ = .2323 _ = .2323e-1 _ = .2323e13434 +_ = 1LL +_ = 1ULL +_ = 9332LL +_ = 9332 +_ = 0x2aLL +_ = 0x2aULL _ = [[ hello world ]] _ = [=[ hello world ]=] _ = [====[ hello world ]====] From 9d2665f8dc08f1f6326df02e399762601e6fb366 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 5 Feb 2014 09:29:39 -0800 Subject: [PATCH 181/554] let colon stubs in assignments get simplified --- moonscript/transform.lua | 11 +++++++++-- moonscript/transform.moon | 10 +++++++++- spec/outputs/class.lua | 12 +++++------- spec/outputs/stub.lua | 13 +++++++------ 4 files changed, 30 insertions(+), 16 deletions(-) diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 449e983a..a56069b6 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -378,6 +378,11 @@ Statement = Transformer({ if num_names == 1 and num_values == 1 then local first_value = values[1] local first_name = names[1] + local first_type = ntype(first_value) + if first_type == "chain" then + first_value = Value:transform_once(self, first_value) + first_type = ntype(first_value) + end local _exp_0 = ntype(first_value) if "block_exp" == _exp_0 then local block_body = first_value[2] @@ -397,6 +402,8 @@ Statement = Transformer({ }) elseif "comprehension" == _exp_0 or "tblcomprehension" == _exp_0 or "foreach" == _exp_0 or "for" == _exp_0 or "while" == _exp_0 then return build.assign_one(first_name, Value:transform_once(self, first_value)) + else + values[1] = first_value end end local transformed @@ -1538,7 +1545,7 @@ Value = Transformer({ local base_name = NameProxy("base") local fn_name = NameProxy("fn") local is_super = ntype(node[2]) == "ref" and node[2][2] == "super" - return self.transform.value(build.block_exp({ + return build.block_exp({ build.assign({ names = { base_name @@ -1580,7 +1587,7 @@ Value = Transformer({ }) } }) - })) + }) end end, block_exp = function(self, node) diff --git a/moonscript/transform.moon b/moonscript/transform.moon index 9175d417..863f1561 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -206,6 +206,12 @@ Statement = Transformer { if num_names == 1 and num_values == 1 first_value = values[1] first_name = names[1] + first_type = ntype first_value + + -- reduce colon stub chain to block exp + if first_type == "chain" + first_value = Value\transform_once @, first_value + first_type = ntype first_value switch ntype first_value when "block_exp" @@ -220,6 +226,8 @@ Statement = Transformer { when "comprehension", "tblcomprehension", "foreach", "for", "while" return build.assign_one first_name, Value\transform_once @, first_value + else + values[1] = first_value -- bubble cascading assigns transformed = if num_values == 1 @@ -922,7 +930,7 @@ Value = Transformer { fn_name = NameProxy "fn" is_super = ntype(node[2]) == "ref" and node[2][2] == "super" - @transform.value build.block_exp { + build.block_exp { build.assign { names: {base_name} values: {node} diff --git a/spec/outputs/class.lua b/spec/outputs/class.lua index 1e3a3015..67227911 100644 --- a/spec/outputs/class.lua +++ b/spec/outputs/class.lua @@ -266,13 +266,11 @@ do local _base_0 = { val = 2323, something = function(self) - return (function() - local _base_1 = _parent_0 - local _fn_0 = _base_1.something - return function(...) - return _fn_0(self, ...) - end - end)() + local _base_1 = _parent_0 + local _fn_0 = _base_1.something + return function(...) + return _fn_0(self, ...) + end end } _base_0.__index = _base_0 diff --git a/spec/outputs/stub.lua b/spec/outputs/stub.lua index 1f02d09c..4ceac088 100644 --- a/spec/outputs/stub.lua +++ b/spec/outputs/stub.lua @@ -4,19 +4,20 @@ local x = { return print(self.val) end } -local fn = (function() +local fn +do local _base_0 = x local _fn_0 = _base_0.val - return function(...) + fn = function(...) return _fn_0(_base_0, ...) end -end)() +end print(fn()) print(x:val()) -x = (function(...) +do local _base_0 = hello(...) local _fn_0 = _base_0.world - return function(...) + x = function(...) return _fn_0(_base_0, ...) end -end)(...) \ No newline at end of file +end \ No newline at end of file From 6307c6a9c1ce60c0b46506ff91d073f70d39ca0e Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 5 Feb 2014 13:07:57 -0800 Subject: [PATCH 182/554] compile before installing locally --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 30b30229..45b90f8a 100644 --- a/Makefile +++ b/Makefile @@ -2,13 +2,13 @@ test:: busted -p "_spec.moon$$" -local: +local: compile luarocks make --local moonscript-dev-1.rockspec global: sudo luarocks make moonscript-dev-1.rockspec -compile: +compile:: bin/moonc moon/ moonscript/ From 727fe0eb1cf627f174ce7c3b5874e1f242cb902b Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 5 Feb 2014 13:08:27 -0800 Subject: [PATCH 183/554] show file in error message in moon loader --- moonscript/base.lua | 2 +- moonscript/base.moon | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/moonscript/base.lua b/moonscript/base.lua index f3b6b392..06b3f6d6 100644 --- a/moonscript/base.lua +++ b/moonscript/base.lua @@ -62,7 +62,7 @@ moon_loader = function(name) file:close() local res, err = loadstring(text, file_path) if not res then - error(err) + error(file_path .. ": " .. err) end return res end diff --git a/moonscript/base.moon b/moonscript/base.moon index fe8e3def..256b0d76 100644 --- a/moonscript/base.moon +++ b/moonscript/base.moon @@ -48,7 +48,7 @@ moon_loader = (name) -> file\close! res, err = loadstring text, file_path if not res - error err + error file_path .. ": " .. err return res From 38d06207ae23daff83acd5f8a11436e983967386 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 8 Feb 2014 18:31:21 -0800 Subject: [PATCH 184/554] enhance missing value compiler error message --- moonscript/compile.lua | 44 ++++++++++++++++++++++++----------------- moonscript/compile.moon | 43 +++++++++++++++++++++++++--------------- 2 files changed, 53 insertions(+), 34 deletions(-) diff --git a/moonscript/compile.lua b/moonscript/compile.lua index 368eead7..2e4ff908 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -474,8 +474,12 @@ do action = node[1] end local fn = self.value_compilers[action] - if not fn then - error("Failed to compile value: " .. dump.value(node)) + if not (fn) then + error({ + "compile-error", + "Failed to find value compiler for: " .. dump.value(node), + node[-1] + }) end local out = fn(self, node, ...) if type(node) == "table" and node[-1] then @@ -659,13 +663,17 @@ do end local format_error format_error = function(msg, pos, file_str) - local line = pos_to_line(file_str, pos) - local line_str - line_str, line = get_closest_line(file_str, line) - line_str = line_str or "" + local line_message + if pos then + local line = pos_to_line(file_str, pos) + local line_str + line_str, line = get_closest_line(file_str, line) + line_str = line_str or "" + line_message = (" [%d] >> %s"):format(line, trim(line_str)) + end return concat({ "Compile error: " .. msg, - (" [%d] >> %s"):format(line, trim(line_str)) + line_message }, "\n") end local value @@ -689,27 +697,27 @@ tree = function(tree, options) return scope:root_stms(tree) end) local success, err = coroutine.resume(runner) - if not success then - local error_msg + if not (success) then + local error_msg, error_pos if type(err) == "table" then local error_type = err[1] - if error_type == "user-error" then - error_msg = err[2] + local _exp_0 = err[1] + if "user-error" == _exp_0 or "compile-error" == _exp_0 then + error_msg, error_pos = unpack(err, 2) else - error_msg = error("Unknown error thrown", util.dump(error_msg)) + error_msg, error_pos = error("Unknown error thrown", util.dump(error_msg)) end else - error_msg = concat({ + error_msg, error_pos = concat({ err, debug.traceback(runner) }, "\n") end - return nil, error_msg, scope.last_pos - else - local lua_code = scope:render() - local posmap = scope._lines:flatten_posmap() - return lua_code, posmap + return nil, error_msg, error_pos or scope.last_pos end + local lua_code = scope:render() + local posmap = scope._lines:flatten_posmap() + return lua_code, posmap end do local data = require("moonscript.data") diff --git a/moonscript/compile.moon b/moonscript/compile.moon index 27ab017c..31762805 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -341,7 +341,12 @@ class Block node[1] fn = @value_compilers[action] - error "Failed to compile value: "..dump.value node if not fn + unless fn + error { + "compile-error" + "Failed to find value compiler for: " .. dump.value node + node[-1] + } out = fn self, node, ... @@ -416,12 +421,15 @@ class RootBlock extends Block table.concat buffer format_error = (msg, pos, file_str) -> - line = pos_to_line file_str, pos - line_str, line = get_closest_line file_str, line - line_str = line_str or "" + line_message = if pos + line = pos_to_line file_str, pos + line_str, line = get_closest_line file_str, line + line_str = line_str or "" + (" [%d] >> %s")\format line, trim line_str + concat { "Compile error: "..msg - (" [%d] >> %s")\format line, trim line_str + line_message }, "\n" value = (value) -> @@ -440,21 +448,24 @@ tree = (tree, options={}) -> scope\root_stms tree success, err = coroutine.resume runner - if not success - error_msg = if type(err) == "table" + + unless success + error_msg, error_pos = if type(err) == "table" error_type = err[1] - if error_type == "user-error" - err[2] - else - error "Unknown error thrown", util.dump error_msg + switch err[1] + when "user-error", "compile-error" + unpack err, 2 + else + -- unknown error, bubble it + error "Unknown error thrown", util.dump error_msg else concat {err, debug.traceback runner}, "\n" - nil, error_msg, scope.last_pos - else - lua_code = scope\render! - posmap = scope._lines\flatten_posmap! - lua_code, posmap + return nil, error_msg, error_pos or scope.last_pos + + lua_code = scope\render! + posmap = scope._lines\flatten_posmap! + lua_code, posmap -- mmmm with data = require "moonscript.data" From df340f7104ca671aae0d398d681950d0501e5ecb Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 8 Feb 2014 18:41:29 -0800 Subject: [PATCH 185/554] avoid creating unnecessary functions when using return keyword with statements and block_exps --- moonscript/transform.lua | 40 +++++++++------ moonscript/transform.moon | 26 +++++++--- spec/inputs/lists.moon | 4 -- spec/inputs/return.moon | 55 ++++++++++++++++++++ spec/outputs/lists.lua | 19 +------ spec/outputs/return.lua | 102 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 201 insertions(+), 45 deletions(-) create mode 100644 spec/inputs/return.moon create mode 100644 spec/outputs/return.lua diff --git a/moonscript/transform.lua b/moonscript/transform.lua index a56069b6..803d5d70 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -329,15 +329,27 @@ Statement = Transformer({ return apply_to_last(body, implicitly_return(self)) end, ["return"] = function(self, node) - node[2] = Value:transform_once(self, node[2]) - if "block_exp" == ntype(node[2]) then - local block_exp = node[2] - local block_body = block_exp[2] - local idx = #block_body - node[2] = block_body[idx] - block_body[idx] = node - return build.group(block_body) + local ret_val = node[2] + local ret_val_type = ntype(ret_val) + if ret_val_type == "explist" and #ret_val == 2 then + ret_val = ret_val[2] + ret_val_type = ntype(ret_val) end + if types.cascading[ret_val_type] then + return implicitly_return(self)(ret_val) + end + if ret_val_type == "chain" or ret_val_type == "comprehension" or ret_val_type == "tblcomprehension" then + ret_val = Value:transform_once(self, ret_val) + if ntype(ret_val) == "block_exp" then + return build.group(apply_to_last(ret_val[2], function(stm) + return { + "return", + stm + } + end)) + end + end + node[2] = ret_val return node end, declare_glob = function(self, node) @@ -1418,13 +1430,11 @@ Value = Transformer({ end end if #node <= 3 then - return (function() - if type(node[3]) == "string" then - return node - else - return convert_part(node[3]) - end - end)() + if type(node[3]) == "string" then + return node + else + return convert_part(node[3]) + end end local e = { "exp", diff --git a/moonscript/transform.moon b/moonscript/transform.moon index 863f1561..059f7d84 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -124,6 +124,7 @@ class Transformer transform: (scope, node, ...) => return node if @seen_nodes[node] + @seen_nodes[node] = true while true transformer = @transformers[ntype node] @@ -131,8 +132,10 @@ class Transformer transformer(scope, node, ...) or node else node + return node if res == node node = res + node bind: (scope) => @@ -173,17 +176,24 @@ Statement = Transformer { apply_to_last body, implicitly_return @ return: (node) => - node[2] = Value\transform_once @, node[2] + ret_val = node[2] + ret_val_type = ntype ret_val + + if ret_val_type == "explist" and #ret_val == 2 + ret_val = ret_val[2] + ret_val_type = ntype ret_val - if "block_exp" == ntype node[2] - block_exp = node[2] - block_body = block_exp[2] + if types.cascading[ret_val_type] + return implicitly_return(@) ret_val - idx = #block_body - node[2] = block_body[idx] - block_body[idx] = node - return build.group block_body + -- flatten things that create block exp + if ret_val_type == "chain" or ret_val_type == "comprehension" or ret_val_type == "tblcomprehension" + ret_val = Value\transform_once @, ret_val + if ntype(ret_val) == "block_exp" + return build.group apply_to_last ret_val[2], (stm)-> + {"return", stm} + node[2] = ret_val node declare_glob: (node) => diff --git a/spec/inputs/lists.moon b/spec/inputs/lists.moon index 91e559e2..c1191857 100644 --- a/spec/inputs/lists.moon +++ b/spec/inputs/lists.moon @@ -69,8 +69,4 @@ print thing for thing in *test -> a = b for row in *rows --- testing implicit return --> x for x in *things --> [x for x in *things] - diff --git a/spec/inputs/return.moon b/spec/inputs/return.moon new file mode 100644 index 00000000..61d3dcad --- /dev/null +++ b/spec/inputs/return.moon @@ -0,0 +1,55 @@ +-- testing `return` propagation + +-> x for x in *things +-> [x for x in *things] + + +-- doesn't make sense on purpose +do + return x for x in *things + +do + return [x for x in *things] + +do + return {x,y for x,y in *things} + +-> + if a + if a + a + else + b + elseif b + if a + a + else + b + else + if a + a + else + b + + +do + return if a + if a + a + else + b + elseif b + if a + a + else + b + else + if a + a + else + b + +-> a\b +do a\b + + diff --git a/spec/outputs/lists.lua b/spec/outputs/lists.lua index 81aaa5b9..4905ee0c 100644 --- a/spec/outputs/lists.lua +++ b/spec/outputs/lists.lua @@ -254,27 +254,10 @@ for _index_0 = 1, #test do local thing = test[_index_0] print(thing) end -local _ -_ = function() +return function() local _list_0 = rows for _index_0 = 1, #_list_0 do local row = _list_0[_index_0] a = b end -end -_ = function() - for _index_0 = 1, #things do - x = things[_index_0] - _ = x - end -end -return function() - local _accum_0 = { } - local _len_0 = 1 - for _index_0 = 1, #things do - x = things[_index_0] - _accum_0[_len_0] = x - _len_0 = _len_0 + 1 - end - return _accum_0 end \ No newline at end of file diff --git a/spec/outputs/return.lua b/spec/outputs/return.lua new file mode 100644 index 00000000..4eeaca20 --- /dev/null +++ b/spec/outputs/return.lua @@ -0,0 +1,102 @@ +local _ +_ = function() + local _list_0 = things + for _index_0 = 1, #_list_0 do + local x = _list_0[_index_0] + _ = x + end +end +_ = function() + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = things + for _index_0 = 1, #_list_0 do + local x = _list_0[_index_0] + _accum_0[_len_0] = x + _len_0 = _len_0 + 1 + end + return _accum_0 +end +do + local _list_0 = things + for _index_0 = 1, #_list_0 do + local x = _list_0[_index_0] + return x + end +end +do + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = things + for _index_0 = 1, #_list_0 do + local x = _list_0[_index_0] + _accum_0[_len_0] = x + _len_0 = _len_0 + 1 + end + return _accum_0 +end +do + local _tbl_0 = { } + local _list_0 = things + for _index_0 = 1, #_list_0 do + local x, y = _list_0[_index_0] + _tbl_0[x] = y + end + return _tbl_0 +end +_ = function() + if a then + if a then + return a + else + return b + end + elseif b then + if a then + return a + else + return b + end + else + if a then + return a + else + return b + end + end +end +do + if a then + if a then + return a + else + return b + end + elseif b then + if a then + return a + else + return b + end + else + if a then + return a + else + return b + end + end +end +_ = function() + local _base_0 = a + local _fn_0 = _base_0.b + return function(...) + return _fn_0(_base_0, ...) + end +end +do + local _base_0 = a + local _fn_0 = _base_0.b + return function(...) + return _fn_0(_base_0, ...) + end +end \ No newline at end of file From da1bc6f8ec0d23e2bd3cf1be0ea592c06c30f8b5 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 15 Feb 2014 14:07:36 -0800 Subject: [PATCH 186/554] use xpcall and get backtrace --- moonscript/parse.lua | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/moonscript/parse.lua b/moonscript/parse.lua index eb4bffc4..f6d84dd5 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -616,13 +616,17 @@ local build_grammar = wrap_env(function() end local tree - local pass, err = pcall(function(...) - tree = self._g:match(str, ...) - end, ...) + local parse_args = {...} + + local pass, err = xpcall(function() + tree = self._g:match(str, unpack(parse_args)) + end, function(err) + return debug.traceback(err, 2) + end) -- regular error, let it bubble up if type(err) == "string" then - error(err) + return nil, err end if not tree then From 437be6efb52902dcd9d8587a642495e797e4f0f5 Mon Sep 17 00:00:00 2001 From: Yorwba Date: Sat, 1 Feb 2014 22:27:48 +0100 Subject: [PATCH 187/554] Fixed lua/moon line mapping --- moonscript/compile.lua | 3 +++ moonscript/compile.moon | 1 + 2 files changed, 4 insertions(+) diff --git a/moonscript/compile.lua b/moonscript/compile.lua index 2e4ff908..379c9c91 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -61,6 +61,9 @@ do local _exp_0 = mtype(l) if "string" == _exp_0 or DelayedLine == _exp_0 then line_no = line_no + 1 + for _ in l:gmatch("\n") do + line_no = line_no + 1 + end out[line_no] = posmap[i] elseif Lines == _exp_0 then local _ diff --git a/moonscript/compile.moon b/moonscript/compile.moon index 31762805..95395669 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -44,6 +44,7 @@ class Lines switch mtype l when "string", DelayedLine line_no += 1 + line_no += 1 for _ in l\gmatch"\n" out[line_no] = posmap[i] when Lines _, line_no = l\flatten_posmap line_no, out From 5f4d476ad0a93cea93cb6da94ffaf55a50937ac5 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 4 Mar 2014 10:12:09 -0800 Subject: [PATCH 188/554] add posmap matching specs --- spec/error_rewriting_spec.moon | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/spec/error_rewriting_spec.moon b/spec/error_rewriting_spec.moon index d2f55c98..3c6d1280 100644 --- a/spec/error_rewriting_spec.moon +++ b/spec/error_rewriting_spec.moon @@ -3,6 +3,8 @@ moonscript = require "moonscript.base" errors = require "moonscript.errors" util = require "moonscript.util" +import unindent from require "spec.helpers" + get_rewritten_line_no = (fname) -> fname = "spec/error_inputs/#{fname}.moon" chunk = moonscript.loadfile fname @@ -28,3 +30,35 @@ describe "error rewriting", -> it "should rewrite line number", -> assert.same get_rewritten_line_no(name), expected_no +describe "line map", -> + import to_lua from require "moonscript.base" + + it "should create line table", -> + moon_code = unindent [[ + print "hello world" + if something + print "cats" + ]] + + lua_code, posmap = assert to_lua moon_code + -- print util.debug_posmap(posmap, moon_code, lua_code) + assert.same { 7, 29, 42, 27 }, posmap + + it "should create line table for multiline string", -> + moon_code = unindent [[ + print "one" + x = [==[ + one + two + thre + yes + no + ]==] + print "two" + ]] + + lua_code, posmap = assert to_lua moon_code + -- print util.debug_posmap(posmap, moon_code, lua_code) + assert.same {[1]: 7, [7]: 19, [8]: 63}, posmap + + From 318192cd41e38806302680649f3e08b00909d3ae Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 4 Mar 2014 10:13:05 -0800 Subject: [PATCH 189/554] fix indentation from patch --- moonscript/compile.moon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/moonscript/compile.moon b/moonscript/compile.moon index 95395669..af7242eb 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -44,7 +44,7 @@ class Lines switch mtype l when "string", DelayedLine line_no += 1 - line_no += 1 for _ in l\gmatch"\n" + line_no += 1 for _ in l\gmatch"\n" out[line_no] = posmap[i] when Lines _, line_no = l\flatten_posmap line_no, out From 7bfbe66c099f758e08e1161a8cf55fd3e6e808ed Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 4 Mar 2014 10:26:29 -0800 Subject: [PATCH 190/554] put changelog in repository --- CHANGELOG.md | 232 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 232 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..b834c435 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,232 @@ + +# MoonScript v0.2.4 (2013-07-02) + +I'm happy to announce [MoonScript][1] version 0.2.4, the CoffeeScript inspired +language that compiles to Lua. It's been about 5 months since the last release. + +## Changes + +* The way the subtraction operator works has changed. There was always a little confusion as to the rules regarding whitespace around it and it was recommended to always add whitespace around the operator when doing subtraction. Not anymore. Hopefully it now [works how you would expect](http://moonscript.org/reference/#considerations). (`a-b` compiles to `a - b` and not `a(-b)` anymore). +* The `moon` library is no longer sets a global variable and instead returns the module. Your code should now be: + +```moon +moon = require "moon" +``` + +* Generated code will reuse local variables when appropriate. Local variables are guaranteed to not have side effects when being accessed as opposed to expressions and global variables. MoonScript will now take advantage of this and reuse those variable without creating and copying to a temporary name. +* Reduced the creation of anonymous functions that are called immediately. + MoonScript uses this technique to convert a series of statements into a single expression. It's inefficient because it allocates a new function object and has to do a function call. It also obfuscates stack traces. MoonScript will flatten these functions into the current scope in a lot of situations now. +* Reduced the amount of code generated for classes. Parent class code it left out if there is no parent. + +## New Things + +* You can now put line breaks inside of string literals. It will be replaced with `\n` in the generated code. + +```moon +x = "hello +world" +``` + +* Added `moonscript.base` module. It's a way of including the `moonscript` module without automatically installing the moonloader. +* You are free to use any whitespace around the name list in an import statement. It has the same rules as an array table, meaning you can delimit names with line breaks. + +```moon +import a, b + c, d from z +``` + +* Added significantly better tests. Previously the testing suite would only verify that code compiled to an expected string. Now there are unit tests that execute the code as well. This will make it easier to change the generated output while still guaranteeing the semantics are the same. + +## Bug Fixes + +* `b` is not longer treated as self assign in `{ a : b }` +* load functions will return `nil` instead of throwing error, as described in documentation +* fixed an issue with `moon.mixin` where it did not work as described + + +# MoonScript v0.2.3-2 (2013-01-29) + +Fixed bug with moonloader not loading anything + +# MoonScript v0.2.3 (2013-01-24) + +Today marks [MoonScript][1] version 0.2.3, the CoffeeScript inspired language +that compiles to Lua. It's been about 3 months since last release. I've got a +couple new features, fixes, Lua 5.2 support and a backwards incompatible +change. + +## Changes + +* For loops when used as expressions will no longer discard nil values when accumulating into an array table. **This is a backwards incompatible change**. Instead you should use the `continue` keyword to filter out iterations you don't want to keep. [Read more here](https://github.com/leafo/moonscript/issues/66). +* The `moonscript` module no longer sets a global value for `moonscript` and instead returns it. You should update your code: + +```moon +moonscript = require "moonscript" +``` + +## New Things + +* Lua 5.2 Support. The compiler can now run in either Lua 5.2 and 5.1 +* A switch `when` clause [can take multiple values](http://moonscript.org/reference/#switch), comma separated. +* Added [destructuring assignment](http://moonscript.org/reference/#destructuring_assignment). +* Added `local *` (and `local ^`) for [hoisting variable declarations](http://moonscript.org/reference/#local_statement) in the current scope +* List comprehensions and line decorators now support numeric loop syntax + +## Bug Fixes + +* Numbers that start with a dot, like `.03`, are correctly parsed +* Fixed typo in `fold` library function +* Fix declaration hoisting inside of class body, works the same as `local *` now + +## Other Stuff + +MoonScript has [made its way into GitHub](https://github.com/github/linguist/pull/246). `.moon` files should start to be recognized in the near future. + + +# MoonScript v0.2.2 (2012-11-03) + +Today marks [MoonScript][1] version 0.2.2, the CoffeeScript inspired language +that compiles to Lua. It's been approximately 11 months since the last release, +and I'd like to apologize for the long gap. Hopefully we'll see more frequent +updates in the future. + +## Changes + +* Compiled [files will now implicitly return](http://moonscript.org/reference/#implicit_returns_on_files) their last statement. Be careful, this might change what `require` returns. + +## New Things + +### The Language + +* Added [`continue` keyword](http://moonscript.org/reference/#continue) for skipping the current iteration in a loop. +* Added [string interpolation](http://moonscript.org/reference/#string_interpolation). +* Added [`do` expression and block](http://moonscript.org/reference/#do). +* Added `unless` as a block and line decorator. Is the inverse of `if`. +* Assignment can be used in an [`if` statement's expression](http://moonscript.org/reference/#with_assignment). +* Added `or=` and `and=` operators. +* `@@` can be prefixed in front of a name to access that name within `self.__class` +* `@` and `@@` can be [used as values](http://moonscript.org/reference/#_and__values) to reference `self` and `self.__class`. +* In class declarations it's possible to [assign to the class object](http://moonscript.org/reference/#class_variables) instead of the instance metatable by prefixing the key with `@`. +* Class methods can access [locals defined within the body](http://moonscript.org/reference/#class_declaration_statements) of the class declaration. +* Super classes are [notified when they are extended](http://moonscript.org/reference/#inheritance) from with an `__inherited` callback. +* Classes can now [implicitly return and be expressions](http://moonscript.org/reference/#anonymous_classes). +* `local` keyword returns, can be used for forward declaration or shadowing a variable. +* String literals can be used as keys in [table literals](http://moonscript.org/reference/#table_literals). +* Call methods on string literals without wrapping in parentheses: `"hello"\upper!` +* Table comprehensions can return a single value that is unpacked into the key and value. +* The expression in a [`with` statement can now be an assignment](http://moonscript.org/reference/#with_statement), to give a name to the expression that is being operated on. + + +### The API + +* The `load` functions can take an [optional last argument of options](http://moonscript.org/reference/#load_functions). + +### The Tools + +* The [online compiler](http://moonscript.org/compiler/) now runs through a web service instead of emscripten, should work reliably on any computer now. +* [Windows binaries](http://moonscript.org/bin/) have been updated. + +## Bug Fixes + +* Significantly improved the [line number rewriter](http://moonscript.org/reference/#error_rewriting). It should now accurately report all line numbers. +* Generic `for` loops correctly parse for multiple values as defined in Lua. +* Update expressions don't fail with certain combinations of precedence. +* All statements/expressions are allowed in a class body, not just some. +* `x = "hello" if something` will extract the declaration of `x` if it's not in scope yet. Preventing an impossible to access variable from being created. +* varargs, `...`, correctly bubble up through automatically generated anonymous functions. +* Compiler doesn't crash if you try to assign something that isn't assignable. +* Numerous other small fixes. See [commit log](https://github.com/leafo/moonscript/commits/master). + + +# MoonScript v0.2.0 (2011-12-12) + +Exactly 3 months ago I released [MoonScript][1]. The CoffeeScript inspired +language that compiles to Lua. Since then I've both written a lot of MoonScript +and enhanced the MoonScript compiler. + +Today I'm proud to release v0.2.0. I've got a handful of new features and bug fixes. + +## Changes + +* `,` is used instead of `:` for delimiting table slice parts. +* Class objects store the metatable of their instances in `__base`. `__base` is also used in inheritance when chaining metatables. + +## New Things + +### The Language + +* Added [key-value table comprehensions][4]. +* Added a [`switch` statement][7]. +* The body of a class can contain arbitrary expressions in addition to assigning properties. `self` in this scope refers to the class itself. +* Class objects themselves support accessing the properties of the superclass they extend (like instances). +* Class objects store their name as a string in the `__name` property. +* [Enhanced the `super` keyword][8] in instance methods. +* Bound methods can be created for an object by using `object\function_name` as a value. Called [function stubs][6]. +* Added `export *` statement to export all assigned names following the statement. +* Added `export ^` statement to export all assigning names that begin with a capital letter following the statement. +* `export` can be used before any assignment or class declaration to export just that assignment (or class declaration). +* Argument lists can be broken up over several lines with trailing comma. +* `:hello` is short hand for `hello: hello` inside of table literal. +* Added `..=` for string concatenation. +* `table.insert` no longer used to build accumlated values in comprehensions. + +### The API + +* Added `loadfile`, `loadstring`, and `dofile` functions to `moonscript` module to load/run MoonScript code. +* Added `to_lua` function to `moonscript` module to convert a MoonScript code string to Lua string. + +### The Tools + +* Created [prebuilt MoonScript Windows executables][2]. +* Wrote a [Textmate/Sublime Text bundle][9]. +* Wrote a [SciTE syntax highlighter with scintillua][10]. +* Created a [SciTE package for Windows][11] that has everything configured. +* Created an [online compiler and snippet site][12] using [emscripten][13]. +* Watch mode works on all platforms now. Uses polling if `inotify` is not + available. + +### Standard Library + +I'm now including a small set of useful functions in a single module called `moon`: + +```moon +require "moon" +``` + +Documentation is [available here][3]. + +## Bug Fixes + +* Windows line endings don't break the parser. +* Fixed issues when using `...` within comprehensions when the compiled code uses an intermediate function in the output. +* Names whose first characters happen to be a keyword don't break parser. +* Return statement can have no arguments +* argument names prefixed with `@` in function definitions work outside of classes work with default values. +* Fixed parse issues with the shorthand values within a `with` block. +* Numerous other small fixes. See [commit log][5]. + +## Other Stuff + +Since the first release, I've written one other project in MoonScript (other than the compiler). It's a static site generator called [sitegen][15]. It's what I now use to generate all of my project pages and this blog. + +# MoonScript 0.1.0 (2011-08-12) + +Initial release + + + [1]: http://moonscript.org + [2]: http://moonscript.org/bin/ + [3]: http://moonscript.org/reference/standard_lib.html + [4]: http://moonscript.org/reference/#table_comprehensions + [5]: https://github.com/leafo/moonscript/commits/master + [6]: http://moonscript.org/reference/#function_stubs + [7]: http://moonscript.org/reference/#switch + [8]: http://moonscript.org/reference/#super + [9]: https://github.com/leafo/moonscript-tmbundle + [10]: https://github.com/leafo/moonscript/tree/master/extra/scintillua + [11]: http://moonscript.org/scite/ + [12]: http://moonscript.org/compiler/ + [13]: http://emscripten.org + [14]: http://twitter.com/moonscript + [15]: http://leafo.net/sitegen/ + From ed939f31674659b7770fb1f33a01a16d1f4ea9e9 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 4 Mar 2014 10:48:39 -0800 Subject: [PATCH 191/554] start filling out changelog for new version --- CHANGELOG.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b834c435..2d9d4c33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,24 @@ +# MoonScript v0.2.4 (TBR) + +## Changes + +Code generation altered. + +* colon stub simplified +* return's statement simplified + +## New Things + +* New code coverage tool built into `moonc` +* New linting tool built into `moonc`, identifies global variable references that don't pass whitelist +* Numbers can have `LL` and `ULL` suffixes for LuaJIT + +## Bugs Fixes + +* Error messages from `moonc` are written to standard error +* Moonloader correctly throws error when moon file can't be parsed, instead of skipping the module + # MoonScript v0.2.4 (2013-07-02) I'm happy to announce [MoonScript][1] version 0.2.4, the CoffeeScript inspired From ba9322901d9b3f47fd736e2c9c7fb62a9fa118ce Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 4 Mar 2014 23:41:07 -0800 Subject: [PATCH 192/554] update changelog for code generation changes --- CHANGELOG.md | 119 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 113 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d9d4c33..b2d0bd87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,113 @@ Code generation altered. -* colon stub simplified +Bound functions will avoid creating an anonymous function unless necessary. + +```moonscript +x = hello\world +``` + +**Before:** + +```lua +local x = (function() + local _base_0 = hello + local _fn_0 = _base_0.world + return function(...) + return _fn_0(_base_0, ...) + end +end)() +``` + +**After:** + +```lua +local x +do + local _base_0 = hello + local _fn_0 = _base_0.world + x = function(...) + return _fn_0(_base_0, ...) + end +end +``` + +Explicit return statement now avoids creating anonymous function for statements +where return can be cascaded into the body. + +```moon +-> + if test1 + return [x for x in *y] + + if test2 + return if true + "yes" + else + "no" + + false +``` + + +**Before:** + +```moonscript +local _ +_ = function() + if test1 then + return (function() + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = y + for _index_0 = 1, #_list_0 do + local x = _list_0[_index_0] + _accum_0[_len_0] = x + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + end + if test2 then + return (function() + if true then + return "yes" + else + return "no" + end + end)() + end + return false +end +``` + +**After:** + +```moonscript +local _ +_ = function() + if test1 then + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = y + for _index_0 = 1, #_list_0 do + local x = _list_0[_index_0] + _accum_0[_len_0] = x + _len_0 = _len_0 + 1 + end + return _accum_0 + end + if test2 then + if true then + return "yes" + else + return "no" + end + end + return false +end +``` + * return's statement simplified ## New Things @@ -18,6 +124,7 @@ Code generation altered. * Error messages from `moonc` are written to standard error * Moonloader correctly throws error when moon file can't be parsed, instead of skipping the module +* Line number rewriting is no longer incorrectly offset due to multiline strings # MoonScript v0.2.4 (2013-07-02) @@ -29,7 +136,7 @@ language that compiles to Lua. It's been about 5 months since the last release. * The way the subtraction operator works has changed. There was always a little confusion as to the rules regarding whitespace around it and it was recommended to always add whitespace around the operator when doing subtraction. Not anymore. Hopefully it now [works how you would expect](http://moonscript.org/reference/#considerations). (`a-b` compiles to `a - b` and not `a(-b)` anymore). * The `moon` library is no longer sets a global variable and instead returns the module. Your code should now be: -```moon +```moonscript moon = require "moon" ``` @@ -42,7 +149,7 @@ moon = require "moon" * You can now put line breaks inside of string literals. It will be replaced with `\n` in the generated code. -```moon +```moonscript x = "hello world" ``` @@ -50,7 +157,7 @@ world" * Added `moonscript.base` module. It's a way of including the `moonscript` module without automatically installing the moonloader. * You are free to use any whitespace around the name list in an import statement. It has the same rules as an array table, meaning you can delimit names with line breaks. -```moon +```moonscript import a, b c, d from z ``` @@ -80,7 +187,7 @@ change. * For loops when used as expressions will no longer discard nil values when accumulating into an array table. **This is a backwards incompatible change**. Instead you should use the `continue` keyword to filter out iterations you don't want to keep. [Read more here](https://github.com/leafo/moonscript/issues/66). * The `moonscript` module no longer sets a global value for `moonscript` and instead returns it. You should update your code: -```moon +```moonscript moonscript = require "moonscript" ``` @@ -209,7 +316,7 @@ Today I'm proud to release v0.2.0. I've got a handful of new features and bug fi I'm now including a small set of useful functions in a single module called `moon`: -```moon +```moonscript require "moon" ``` From 84e35232df374c7c842748b984ebdb7aba293dd8 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 5 Mar 2014 00:28:05 -0800 Subject: [PATCH 193/554] documentation for code coverage and linter --- CHANGELOG.md | 2 - docs/reference.md | 162 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 161 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b2d0bd87..d988cd52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -112,8 +112,6 @@ _ = function() end ``` -* return's statement simplified - ## New Things * New code coverage tool built into `moonc` diff --git a/docs/reference.md b/docs/reference.md index 42992670..bb5275a1 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -1688,6 +1688,47 @@ If you want to disable [error rewriting](#error_rewriting), you can pass the `-d` flag. A full list of flags can be seen by passing the `-h` or `--help` flag. +### Code Coverage + +`moon` lets you run a MoonScript file while keeping track of which lines +are executed with the `-c` flag. + +For example, consider the following `.moon` file: + +```moononly +-- test.moon +first = -> + print "hello" + +second = -> + print "world" + +first! +``` + +We can execute and get a glance of which lines ran: + +```bash +$ moon -c test.moon +``` + +The following output is produced: + +``` +------| @cool.moon + 1| -- test.moon +* 2| first = -> +* 3| print "hello" + 4| +* 5| second = -> + 6| print "world" + 7| +* 8| first! + 9| +``` + +The star next to the line means that it was executed. Blank lines are not +considered when running so by default they don't get marked as executed. ## `moonc` @@ -1713,9 +1754,128 @@ compiled automatically. A full list of flags can be seen by passing the `-h` or `--help` flag. +### Linter + +`moonc` contains a [lint](http://en.wikipedia.org/wiki/Lint_(software)) tool +for statically detecting potential problems with code. The current linter only +has one test: it detects the use of global variables. + +You can execute the linter with the `-l` flag. When the linting flag is +provided only linting takes place and no compiled code is generated. + +```bash +moonc -l file1.moon file2.moon +``` + +Like when compiling, you can also pass a directory as a command line argument +to recursively process all the `.moon` files. + +#### Global Variable Checking + +It's considered good practice to avoid using global variables and create local +variables for all the values referenced. A good case for not using global +variables is that you can analyize the code ahead of time without the need to +execute it to find references to undeclared variables. + +MoonScript makes it difficult to declare global variables by forcing you to be +explicit with the `export` keyword, so it's a good candidate for doing this +kind of linting. + +Consider the following program with a typo: (`my_number` is spelled wrong as +`my_nmuber` in the function) + +```moononly +-- lint_example.moon +my_number = 1234 + +some_function = -> + -- a contrived example with a small chance to pass + if math.random() < 0.01 + my_nmuber + 10 + +some_function! +``` + +Although there is a bug in this code, it rarely happens during execution. It's +more likely to be missed during development and cause problems in the future. + +Running the linter immediately identifies the problem: + +```bash +$ moonc -l lint_example.moon +``` + +Outputs: + +``` +./lint_example.moon + +line 7: accessing global my_nmuber +================================== +> my_nmuber + 10 + +``` + +##### Global Variable Whitelist + +In most circumstances it's impossible to avoid using some global variables. For +example, to access any of the built in modules or functions you typically +access them globally. + +For this reason a global variable whitelist is used. It's a list of global +variables that are allowed to be used. A default whitelist is provided that +contains all of Lua's built in functions and modules. + +You can create your own entires in the whitelist as well. For example, the +testing framework [Busted](http://olivinelabs.com/busted) uses a collection of +global functions (like `describe`, `before_each`, `setup`) to make writing +tests easy. + +It would be nice if we could allow all of those global functions to be called +for `.moon` files located in the `spec/` directory. We can do that by creating +a `lint_config` file. + +`lint_config` is a regular MoonScript or Lua file that provides configuration +for the linter. One of those settings is `whitelist_globals`. + +To create a configuration for Busted we might do something like this: + +```moononly +-- lint_config.moon +{ + whitelist_globals: { + ["spec/"]: { + "it", "describe", "setup", "teardown", + "before_each", "after_each", "pending" + } + } +} +``` + +Compile the file: + +```bash +$ moonc lint_config.moon +``` + +Then run the linter on your entire project: + +```bash +$ moonc -l . +``` + +The whitelisted global references in `spec/` will no longer raise notices. + +The `whitelist_globals` property of the `lint_config` is a table where the keys +are Lua patterns that match file names, and the values are an array of globals +that are allowed. + +Multiple patterns in `whitelist_globals` can match a single file, the union of +the allowed globals will be used when linting that file. + # License (MIT) - Copyright (C) 2013 by Leaf Corcoran + Copyright (C) 2014 by Leaf Corcoran Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 686261c983c5603341f10f325710c8ff6e391b02 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 5 Mar 2014 00:31:34 -0800 Subject: [PATCH 194/554] clean out changelog --- CHANGELOG.md | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d988cd52..367e6f9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,5 @@ -# MoonScript v0.2.4 (TBR) +# MoonScript v0.2.5 (TBR) ## Changes @@ -126,9 +126,6 @@ end # MoonScript v0.2.4 (2013-07-02) -I'm happy to announce [MoonScript][1] version 0.2.4, the CoffeeScript inspired -language that compiles to Lua. It's been about 5 months since the last release. - ## Changes * The way the subtraction operator works has changed. There was always a little confusion as to the rules regarding whitespace around it and it was recommended to always add whitespace around the operator when doing subtraction. Not anymore. Hopefully it now [works how you would expect](http://moonscript.org/reference/#considerations). (`a-b` compiles to `a - b` and not `a(-b)` anymore). @@ -175,11 +172,6 @@ Fixed bug with moonloader not loading anything # MoonScript v0.2.3 (2013-01-24) -Today marks [MoonScript][1] version 0.2.3, the CoffeeScript inspired language -that compiles to Lua. It's been about 3 months since last release. I've got a -couple new features, fixes, Lua 5.2 support and a backwards incompatible -change. - ## Changes * For loops when used as expressions will no longer discard nil values when accumulating into an array table. **This is a backwards incompatible change**. Instead you should use the `continue` keyword to filter out iterations you don't want to keep. [Read more here](https://github.com/leafo/moonscript/issues/66). @@ -210,11 +202,6 @@ MoonScript has [made its way into GitHub](https://github.com/github/linguist/pul # MoonScript v0.2.2 (2012-11-03) -Today marks [MoonScript][1] version 0.2.2, the CoffeeScript inspired language -that compiles to Lua. It's been approximately 11 months since the last release, -and I'd like to apologize for the long gap. Hopefully we'll see more frequent -updates in the future. - ## Changes * Compiled [files will now implicitly return](http://moonscript.org/reference/#implicit_returns_on_files) their last statement. Be careful, this might change what `require` returns. @@ -265,12 +252,6 @@ updates in the future. # MoonScript v0.2.0 (2011-12-12) -Exactly 3 months ago I released [MoonScript][1]. The CoffeeScript inspired -language that compiles to Lua. Since then I've both written a lot of MoonScript -and enhanced the MoonScript compiler. - -Today I'm proud to release v0.2.0. I've got a handful of new features and bug fixes. - ## Changes * `,` is used instead of `:` for delimiting table slice parts. From ea282f23d213a2ad8c784f4f04a907b5085443c0 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 5 Mar 2014 00:33:18 -0800 Subject: [PATCH 195/554] bump version :first_quarter_moon_with_face: --- CHANGELOG.md | 2 +- docs/reference.md | 2 +- docs/standard_lib.md | 2 +- moonscript/version.lua | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 367e6f9c..585cf30d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,5 @@ -# MoonScript v0.2.5 (TBR) +# MoonScript v0.2.5 (2014-3-5) ## Changes diff --git a/docs/reference.md b/docs/reference.md index bb5275a1..8207636d 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -1,6 +1,6 @@ target: reference/index template: reference - title: MoonScript v0.2.4 - Language Guide + title: MoonScript v0.2.5 - Language Guide short_name: lang -- MoonScript is a programming language that compiles to diff --git a/docs/standard_lib.md b/docs/standard_lib.md index 95c2a552..d76fe8fb 100644 --- a/docs/standard_lib.md +++ b/docs/standard_lib.md @@ -1,6 +1,6 @@ target: reference/standard_lib template: reference - title: MoonScript v0.2.4 - Standard Library + title: MoonScript v0.2.5 - Standard Library short_name: stdlib -- diff --git a/moonscript/version.lua b/moonscript/version.lua index ce19da42..771bf129 100644 --- a/moonscript/version.lua +++ b/moonscript/version.lua @@ -1,7 +1,7 @@ module("moonscript.version", package.seeall) -version = "0.2.4" +version = "0.2.5" function print_version() print("MoonScript version "..version) end From 8851f803fb60b18d4b85217b231999c9dff65b8b Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 5 Mar 2014 10:25:49 -0800 Subject: [PATCH 196/554] documentation tweaks, reorder changelog --- CHANGELOG.md | 24 +++++++++--------- docs/reference.md | 63 ++++++++++++++++++++++++++++------------------- 2 files changed, 49 insertions(+), 38 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 585cf30d..4464d817 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,19 @@ # MoonScript v0.2.5 (2014-3-5) -## Changes +## New Things + +* New [code coverage tool](http://moonscript.org/reference/#code_coverage) built into `moonc` +* New [linting tool](http://moonscript.org/reference/#linter) built into `moonc`, identifies global variable references that don't pass whitelist +* Numbers can have `LL` and `ULL` suffixes for LuaJIT + +## Bugs Fixes + +* Error messages from `moonc` are written to standard error +* Moonloader correctly throws error when moon file can't be parsed, instead of skipping the module +* Line number rewriting is no longer incorrectly offset due to multiline strings -Code generation altered. +## Code Generation Bound functions will avoid creating an anonymous function unless necessary. @@ -112,17 +122,7 @@ _ = function() end ``` -## New Things -* New code coverage tool built into `moonc` -* New linting tool built into `moonc`, identifies global variable references that don't pass whitelist -* Numbers can have `LL` and `ULL` suffixes for LuaJIT - -## Bugs Fixes - -* Error messages from `moonc` are written to standard error -* Moonloader correctly throws error when moon file can't be parsed, instead of skipping the module -* Line number rewriting is no longer incorrectly offset due to multiline strings # MoonScript v0.2.4 (2013-07-02) diff --git a/docs/reference.md b/docs/reference.md index 8207636d..d9ec83c8 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -1235,6 +1235,19 @@ import \add from my_module print add 22 -- equivalent to calling my_module\get 22 ``` +When handing multiple imports you can substitute the comma with a newline and +any amount of whitespace. When working with a lot of imports you might write +something like this: + +```moon +import + assert_csrf + assert_timezone + not_found + require_login + from require "helpers" +``` + ## With Statement A common pattern involving the creation of an object is calling a series of @@ -1521,25 +1534,27 @@ By default, a file will also implicitly return like a function. This is useful for writing modules, where you can put your module's table as the last statement in the file so it is returned when loaded with `require`. - ### Writing Modules Lua 5.2 has removed the `module` function for creating modules. It is recommended to return a table instead when defining a module. -The `with` statement along with implicit return on a file provides a convenient -way to do this: - +We can cleanly define modules by using the shorthand hash table key/value +syntax: ```moonret --- my_library.moon -with _M = {} - .SOME_CONSTANT = 100 - .some_function = -> print .SOME_CONSTANT +MY_CONSTANT = "hello" +my_function = -> print "the function" +my_second_function = -> print "another function" + +{ :my_function, :my_second_function, :MY_CONSTANT} ``` +If you need to forward declare your values so you can access them regardless of +their written order you can add `local *` to the top of your file. + # MoonScript API ## `moonscript` Module @@ -1714,18 +1729,16 @@ $ moon -c test.moon The following output is produced: -``` -------| @cool.moon - 1| -- test.moon -* 2| first = -> -* 3| print "hello" - 4| -* 5| second = -> - 6| print "world" - 7| -* 8| first! - 9| -``` + ------| @cool.moon + 1| -- test.moon + * 2| first = -> + * 3| print "hello" + 4| + * 5| second = -> + 6| print "world" + 7| + * 8| first! + 9| The star next to the line means that it was executed. Blank lines are not considered when running so by default they don't get marked as executed. @@ -1807,14 +1820,12 @@ $ moonc -l lint_example.moon Outputs: -``` -./lint_example.moon + ./lint_example.moon -line 7: accessing global my_nmuber -================================== -> my_nmuber + 10 + line 7: accessing global my_nmuber + ================================== + > my_nmuber + 10 -``` ##### Global Variable Whitelist From db8f5398fc2d9de842cf535ae10c69e9c6868bdb Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 5 Mar 2014 23:09:43 -0800 Subject: [PATCH 197/554] append avoids creating table for varargs --- moonscript/compile.lua | 40 ++++++++++++++++------------------------ moonscript/compile.moon | 26 ++++++++++++-------------- 2 files changed, 28 insertions(+), 38 deletions(-) diff --git a/moonscript/compile.lua b/moonscript/compile.lua index 379c9c91..e5515a56 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -150,38 +150,30 @@ end do local _base_0 = { pos = nil, - _append_single = function(self, item) - if Line == mtype(item) then - if not (self.pos) then - self.pos = item.pos - end - for _index_0 = 1, #item do - local value = item[_index_0] - self:_append_single(value) - end - else - insert(self, item) - end - return nil - end, append_list = function(self, items, delim) for i = 1, #items do - self:_append_single(items[i]) + self:append(items[i]) if i < #items then insert(self, delim) end end return nil end, - append = function(self, ...) - local _list_0 = { - ... - } - for _index_0 = 1, #_list_0 do - local item = _list_0[_index_0] - self:_append_single(item) + append = function(self, first, ...) + if Line == mtype(first) then + if not (self.pos) then + self.pos = first.pos + end + for _index_0 = 1, #first do + local value = first[_index_0] + self:append(value) + end + else + insert(self, first) + end + if ... then + return self:append(...) end - return nil end, render = function(self, buffer) local current = { } @@ -209,7 +201,7 @@ do insert(current, chunk) end end - if #current > 0 then + if current[1] then add_current() end return buffer diff --git a/moonscript/compile.moon b/moonscript/compile.moon index af7242eb..c8b3a549 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -97,24 +97,22 @@ class Lines class Line pos: nil - _append_single: (item) => - if Line == mtype item - -- print "appending line to line", item.pos, item - @pos = item.pos unless @pos -- bubble pos if there isn't one - @_append_single value for value in *item - else - insert self, item - nil - append_list: (items, delim) => for i = 1,#items - @_append_single items[i] + @append items[i] if i < #items then insert self, delim nil - append: (...) => - @_append_single item for item in *{...} - nil + append: (first, ...) => + if Line == mtype first + -- print "appending line to line", first.pos, first + @pos = first.pos unless @pos -- bubble pos if there isn't one + @append value for value in *first + else + insert self, first + + if ... + @append ... -- todo: try to remove concats from here render: (buffer) => @@ -137,7 +135,7 @@ class Line else insert current, chunk - if #current > 0 + if current[1] add_current! buffer From 3b81b84a9a191063b16110c9f1912a903fc3e8a2 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 5 Mar 2014 23:18:15 -0800 Subject: [PATCH 198/554] create two entries in posmap for multi-line lines --- moonscript/compile.lua | 1 + moonscript/compile.moon | 2 ++ 2 files changed, 3 insertions(+) diff --git a/moonscript/compile.lua b/moonscript/compile.lua index e5515a56..1fc05ceb 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -61,6 +61,7 @@ do local _exp_0 = mtype(l) if "string" == _exp_0 or DelayedLine == _exp_0 then line_no = line_no + 1 + out[line_no] = posmap[i] for _ in l:gmatch("\n") do line_no = line_no + 1 end diff --git a/moonscript/compile.moon b/moonscript/compile.moon index c8b3a549..6bcc9491 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -44,6 +44,8 @@ class Lines switch mtype l when "string", DelayedLine line_no += 1 + out[line_no] = posmap[i] + line_no += 1 for _ in l\gmatch"\n" out[line_no] = posmap[i] when Lines From d0cdf220e20b7f04bafc2cf47a6fcfd1408f31c9 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 6 Mar 2014 13:05:17 -0800 Subject: [PATCH 199/554] fix indent and broken lint link --- docs/reference.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/reference.md b/docs/reference.md index d9ec83c8..8bcfacf4 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -90,7 +90,7 @@ without an escape sequence: ```moon some_string = "Here is a string - that has a line break in it." + that has a line break in it." ``` ## Function Literals @@ -1769,7 +1769,7 @@ A full list of flags can be seen by passing the `-h` or `--help` flag. ### Linter -`moonc` contains a [lint](http://en.wikipedia.org/wiki/Lint_(software)) tool +`moonc` contains a [lint][1] tool for statically detecting potential problems with code. The current linter only has one test: it detects the use of global variables. @@ -1802,9 +1802,9 @@ Consider the following program with a typo: (`my_number` is spelled wrong as my_number = 1234 some_function = -> - -- a contrived example with a small chance to pass - if math.random() < 0.01 - my_nmuber + 10 + -- a contrived example with a small chance to pass + if math.random() < 0.01 + my_nmuber + 10 some_function! ``` @@ -1854,12 +1854,12 @@ To create a configuration for Busted we might do something like this: ```moononly -- lint_config.moon { - whitelist_globals: { - ["spec/"]: { - "it", "describe", "setup", "teardown", - "before_each", "after_each", "pending" - } - } + whitelist_globals: { + ["spec/"]: { + "it", "describe", "setup", "teardown", + "before_each", "after_each", "pending" + } + } } ``` @@ -1907,4 +1907,4 @@ the allowed globals will be used when linting that file. THE SOFTWARE. - + [1]: http://en.wikipedia.org/wiki/Lint_(software) From dd7e9924dd7beac2a8c01ea0ed49ebb7d98e5bdf Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Mon, 10 Mar 2014 22:24:24 -0700 Subject: [PATCH 200/554] remove left over args --- moonscript/base.lua | 4 ++-- moonscript/base.moon | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/moonscript/base.lua b/moonscript/base.lua index 06b3f6d6..f1bc036c 100644 --- a/moonscript/base.lua +++ b/moonscript/base.lua @@ -33,7 +33,7 @@ to_lua = function(text, options) end if "string" ~= type(text) then local t = type(text) - return nil, "expecting string (got " .. t .. ")", 2 + return nil, "expecting string (got " .. t .. ")" end local tree, err = parse.string(text) if not tree then @@ -41,7 +41,7 @@ to_lua = function(text, options) end local code, ltable, pos = compile.tree(tree, options) if not code then - return nil, compile.format_error(ltable, pos, text), 2 + return nil, compile.format_error(ltable, pos, text) end return code, ltable end diff --git a/moonscript/base.moon b/moonscript/base.moon index 256b0d76..1988d063 100644 --- a/moonscript/base.moon +++ b/moonscript/base.moon @@ -22,7 +22,7 @@ create_moonpath = (package_path) -> to_lua = (text, options={}) -> if "string" != type text t = type text - return nil, "expecting string (got ".. t ..")", 2 + return nil, "expecting string (got ".. t ..")" tree, err = parse.string text if not tree @@ -30,7 +30,7 @@ to_lua = (text, options={}) -> code, ltable, pos = compile.tree tree, options if not code - return nil, compile.format_error(ltable, pos, text), 2 + return nil, compile.format_error(ltable, pos, text) code, ltable From 5c6b298324c62b525fbc1b58ef8c1a1bb3c01560 Mon Sep 17 00:00:00 2001 From: mpeterv Date: Thu, 13 Mar 2014 19:16:07 +0400 Subject: [PATCH 201/554] Removed some unused variables --- moonscript/base.lua | 1 - moonscript/base.moon | 2 +- moonscript/compile.lua | 2 -- moonscript/compile.moon | 2 -- moonscript/compile/statement.lua | 1 - moonscript/compile/statement.moon | 1 - moonscript/parse.lua | 36 ++------------------------- moonscript/transform/destructure.lua | 1 - moonscript/transform/destructure.moon | 2 -- 9 files changed, 3 insertions(+), 45 deletions(-) diff --git a/moonscript/base.lua b/moonscript/base.lua index f1bc036c..fd5a8f9c 100644 --- a/moonscript/base.lua +++ b/moonscript/base.lua @@ -128,7 +128,6 @@ return { insert_loader = insert_loader, remove_loader = remove_loader, to_lua = to_lua, - moon_chunk = moon_chunk, moon_loader = moon_loader, dirsep = dirsep, dofile = dofile, diff --git a/moonscript/base.moon b/moonscript/base.moon index 1988d063..7aa39902 100644 --- a/moonscript/base.moon +++ b/moonscript/base.moon @@ -102,7 +102,7 @@ remove_loader = -> { _NAME: "moonscript" - :insert_loader, :remove_loader, :to_lua, :moon_chunk, :moon_loader, :dirsep, + :insert_loader, :remove_loader, :to_lua, :moon_loader, :dirsep, :dofile, :loadfile, :loadstring } diff --git a/moonscript/compile.lua b/moonscript/compile.lua index 1fc05ceb..ccb2e936 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -102,7 +102,6 @@ do end end insert(buffer, "\n") - local last = l elseif Lines == _exp_0 then l:flatten(indent and indent .. indent_char or indent_char, buffer) else @@ -696,7 +695,6 @@ tree = function(tree, options) if not (success) then local error_msg, error_pos if type(err) == "table" then - local error_type = err[1] local _exp_0 = err[1] if "user-error" == _exp_0 or "compile-error" == _exp_0 then error_msg, error_pos = unpack(err, 2) diff --git a/moonscript/compile.moon b/moonscript/compile.moon index 6bcc9491..ac6c4638 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -76,7 +76,6 @@ class Lines insert buffer, ";" insert buffer, "\n" - last = l when Lines l\flatten indent and indent .. indent_char or indent_char, buffer else @@ -452,7 +451,6 @@ tree = (tree, options={}) -> unless success error_msg, error_pos = if type(err) == "table" - error_type = err[1] switch err[1] when "user-error", "compile-error" unpack err, 2 diff --git a/moonscript/compile/statement.lua b/moonscript/compile/statement.lua index abccd627..7b6ccb0f 100644 --- a/moonscript/compile/statement.lua +++ b/moonscript/compile/statement.lua @@ -1,5 +1,4 @@ local util = require("moonscript.util") -local data = require("moonscript.data") local reversed, unpack reversed, unpack = util.reversed, util.unpack local ntype diff --git a/moonscript/compile/statement.moon b/moonscript/compile/statement.moon index 996b3855..9d0f43a7 100644 --- a/moonscript/compile/statement.moon +++ b/moonscript/compile/statement.moon @@ -1,6 +1,5 @@ util = require "moonscript.util" -data = require "moonscript.data" import reversed, unpack from util import ntype from require "moonscript.types" diff --git a/moonscript/parse.lua b/moonscript/parse.lua index f6d84dd5..4d75b2d2 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -10,7 +10,6 @@ local types = require"moonscript.types" local ntype = types.ntype -local dump = util.dump local trim = util.trim local getfenv = util.getfenv @@ -126,7 +125,7 @@ end local function extract_line(str, start_pos) str = str:sub(start_pos) - m = str:match"^(.-)\n" + local m = str:match"^(.-)\n" if m then return m end return str:match"^.-$" end @@ -148,21 +147,6 @@ local function pos(patt) return (lpeg.Cp() * patt) / insert_pos end -local function got(what) - return Cmt("", function(str, pos, ...) - local cap = {...} - print("++ got "..what, "["..extract_line(str, pos).."]") - return true - end) -end - -local function flatten(tbl) - if #tbl == 1 then - return tbl[1] - end - return tbl -end - local function flatten_or_mark(name) return function(tbl) if #tbl == 1 then return tbl[1] end @@ -234,7 +218,7 @@ end local function simple_string(delim, allow_interpolation) local inner = P('\\'..delim) + "\\\\" + (1 - P(delim)) if allow_interpolation then - inter = symx"#{" * V"Exp" * sym"}" + local inter = symx"#{" * V"Exp" * sym"}" inner = (C((inner - inter)^1) + inter / mark"interpolate")^0 else inner = C(inner^0) @@ -280,16 +264,6 @@ local function wrap_decorator(stm, dec) return { "decorated", stm, dec } end --- wrap if statement if there is a conditional decorator -local function wrap_if(stm, cond) - if cond then - local pass, fail = unpack(cond) - if fail then fail = {"else", {fail}} end - return {"if", cond[2], {stm}, fail} - end - return stm -end - local function check_lua_string(str, pos, right, left) return #left == #right end @@ -343,18 +317,12 @@ local build_grammar = wrap_env(function() return true end - local function enable_do(str_pos) - _do_stack:push(true) - return true - end - local function pop_do(str, pos) if nil == _do_stack:pop() then error("unexpected do pop") end return true end local DisableDo = Cmt("", disable_do) - local EnableDo = Cmt("", enable_do) local PopDo = Cmt("", pop_do) local keywords = {} diff --git a/moonscript/transform/destructure.lua b/moonscript/transform/destructure.lua index cb450711..f7a5166c 100644 --- a/moonscript/transform/destructure.lua +++ b/moonscript/transform/destructure.lua @@ -23,7 +23,6 @@ do local _obj_0 = require("moonscript.errors") user_error = _obj_0.user_error end -local util = require("moonscript.util") local join join = function(...) do diff --git a/moonscript/transform/destructure.moon b/moonscript/transform/destructure.moon index 274e6ed3..1547ccfc 100644 --- a/moonscript/transform/destructure.moon +++ b/moonscript/transform/destructure.moon @@ -6,8 +6,6 @@ import unpack from require "moonscript.util" import user_error from require "moonscript.errors" -util = require "moonscript.util" - join = (...) -> with out = {} i = 1 From 592d4b007433aaa6476ba71698025cc816f7f497 Mon Sep 17 00:00:00 2001 From: mpeterv Date: Sat, 22 Mar 2014 10:53:40 +0400 Subject: [PATCH 202/554] Readded got() --- moonscript/parse.lua | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 4d75b2d2..63458592 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -147,6 +147,14 @@ local function pos(patt) return (lpeg.Cp() * patt) / insert_pos end +local function got(what) + return Cmt("", function(str, pos, ...) + local cap = {...} + print("++ got "..what, "["..extract_line(str, pos).."]") + return true + end) +end + local function flatten_or_mark(name) return function(tbl) if #tbl == 1 then return tbl[1] end From 1527a5f696f1dda718f44bdd28b6615f2ab650cf Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 23 Mar 2014 23:45:38 -0700 Subject: [PATCH 203/554] update broken spec --- spec/error_rewriting_spec.moon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/error_rewriting_spec.moon b/spec/error_rewriting_spec.moon index 3c6d1280..6493c654 100644 --- a/spec/error_rewriting_spec.moon +++ b/spec/error_rewriting_spec.moon @@ -59,6 +59,6 @@ describe "line map", -> lua_code, posmap = assert to_lua moon_code -- print util.debug_posmap(posmap, moon_code, lua_code) - assert.same {[1]: 7, [7]: 19, [8]: 63}, posmap + assert.same {[1]: 7, [2]: 19, [7]: 19, [8]: 63}, posmap From d6f0e89cdbedaa75ac22689dfe306c223edd68db Mon Sep 17 00:00:00 2001 From: Conor Heine Date: Tue, 27 May 2014 22:33:24 -0700 Subject: [PATCH 204/554] added '-o file' flag to control output name/destination --- bin/moonc | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/bin/moonc b/bin/moonc index dec5ad7c..b273dfdf 100755 --- a/bin/moonc +++ b/bin/moonc @@ -9,7 +9,7 @@ local dump_tree = require"moonscript.dump".tree local alt_getopt = require "alt_getopt" local lfs = require "lfs" -local opts, ind = alt_getopt.get_opts(arg, "lvhwt:pTXb", { +local opts, ind = alt_getopt.get_opts(arg, "lvhwt:o:pTXb", { print = "p", tree = "T", version = "v", help = "h", lint = "l" }) @@ -22,6 +22,7 @@ local help = [[Usage: %s [options] files... -h Print this message -w Watch file/directory -t path Specify where to place compiled files + -o file Write output to file -p Write output to standard out -T Write parse tree instead of code (to stdout) -X Write line rewrite map instead of code (to stdout) @@ -372,7 +373,12 @@ if opts.w then end for fname in protected do - local target = target_dir..convert_path(fname) + local target + if opts.o then + target = opts.o + else + target = target_dir..convert_path(fname) + end local success, err = compile_and_write(fname, target) if not success then io.stderr:write(table.concat({ @@ -399,7 +405,13 @@ elseif opts.l then end else for _, fname in ipairs(files) do - local success, err = compile_and_write(fname, target_dir..convert_path(fname)) + local target + if opts.o then + target = opts.o + else + target = target_dir..convert_path(fname) + end + local success, err = compile_and_write(fname, target) if not success then io.stderr:write(fname .. "\t" .. err .. "\n") os.exit(1) From cb6cb86db89d7a1215266131e29621364073eb02 Mon Sep 17 00:00:00 2001 From: Conor Heine Date: Tue, 27 May 2014 22:58:02 -0700 Subject: [PATCH 205/554] returning a table rather than using module() --- moonscript/version.lua | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/moonscript/version.lua b/moonscript/version.lua index 771bf129..116b2971 100644 --- a/moonscript/version.lua +++ b/moonscript/version.lua @@ -1,7 +1,9 @@ -module("moonscript.version", package.seeall) - version = "0.2.5" -function print_version() - print("MoonScript version "..version) -end + +return { + version = version, + print_version = function() + print("MoonScript version "..version) + end +} From 6046b56b07589d5ecb0c6ef8fdbad973bc117973 Mon Sep 17 00:00:00 2001 From: Conor Heine Date: Tue, 27 May 2014 23:41:19 -0700 Subject: [PATCH 206/554] forgot to localize version --- moonscript/version.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/moonscript/version.lua b/moonscript/version.lua index 116b2971..bbbf0a82 100644 --- a/moonscript/version.lua +++ b/moonscript/version.lua @@ -1,5 +1,5 @@ -version = "0.2.5" +local version = "0.2.5" return { version = version, From 76475da55de421ca0114b29e1dd83793a869d619 Mon Sep 17 00:00:00 2001 From: Conor Heine Date: Thu, 29 May 2014 12:57:47 -0700 Subject: [PATCH 207/554] moved version to moon file --- moonscript/version.lua | 4 +--- moonscript/version.moon | 8 ++++++++ 2 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 moonscript/version.moon diff --git a/moonscript/version.lua b/moonscript/version.lua index bbbf0a82..8dda91c7 100644 --- a/moonscript/version.lua +++ b/moonscript/version.lua @@ -1,9 +1,7 @@ - local version = "0.2.5" - return { version = version, print_version = function() - print("MoonScript version "..version) + return print("MoonScript version " .. tostring(version)) end } diff --git a/moonscript/version.moon b/moonscript/version.moon new file mode 100644 index 00000000..bf801c36 --- /dev/null +++ b/moonscript/version.moon @@ -0,0 +1,8 @@ + +version = "0.2.5" + +{ + version: version, + print_version: -> + print "MoonScript version #{version}" +} From fa6054f819d5b259a7ebf8655026dd1d4663fe1b Mon Sep 17 00:00:00 2001 From: Conor Heine Date: Thu, 29 May 2014 13:00:04 -0700 Subject: [PATCH 208/554] fixed whitespace --- moonscript/version.moon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/moonscript/version.moon b/moonscript/version.moon index bf801c36..62886737 100644 --- a/moonscript/version.moon +++ b/moonscript/version.moon @@ -4,5 +4,5 @@ version = "0.2.5" { version: version, print_version: -> - print "MoonScript version #{version}" + print "MoonScript version #{version}" } From c73762e00ee2e9bb9b2ec70c49e1e24f132a6c09 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 6 Jun 2014 14:36:03 -0700 Subject: [PATCH 209/554] prefix file path with @ when loading string --- moonscript/base.lua | 4 ++-- moonscript/base.moon | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/moonscript/base.lua b/moonscript/base.lua index fd5a8f9c..9c74de4b 100644 --- a/moonscript/base.lua +++ b/moonscript/base.lua @@ -60,7 +60,7 @@ moon_loader = function(name) if file then local text = file:read("*a") file:close() - local res, err = loadstring(text, file_path) + local res, err = loadstring(text, "@" .. tostring(file_path)) if not res then error(file_path .. ": " .. err) end @@ -90,7 +90,7 @@ loadfile = function(fname, ...) end local text = assert(file:read("*a")) file:close() - return loadstring(text, fname, ...) + return loadstring(text, "@" .. tostring(fname), ...) end dofile = function(...) local f = assert(loadfile(...)) diff --git a/moonscript/base.moon b/moonscript/base.moon index 7aa39902..371628cc 100644 --- a/moonscript/base.moon +++ b/moonscript/base.moon @@ -46,7 +46,7 @@ moon_loader = (name) -> if file text = file\read "*a" file\close! - res, err = loadstring text, file_path + res, err = loadstring text, "@#{file_path}" if not res error file_path .. ": " .. err @@ -72,7 +72,7 @@ loadfile = (fname, ...) -> return nil, err unless file text = assert file\read "*a" file\close! - loadstring text, fname, ... + loadstring text, "@#{fname}", ... -- throws errros dofile = (...) -> From f92e046d13f98f34ff2bfc8dd0793122ff18706b Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 7 Jun 2014 00:04:26 -0700 Subject: [PATCH 210/554] add spec helpers --- spec/helpers.moon | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 spec/helpers.moon diff --git a/spec/helpers.moon b/spec/helpers.moon new file mode 100644 index 00000000..c5ddf9f5 --- /dev/null +++ b/spec/helpers.moon @@ -0,0 +1,9 @@ + +-- remove front indentation from a multiline string, making it suitable to be +-- parsed +unindent = (str) -> + indent = str\match "^%s+" + return str unless indent + (str\gsub("\n#{indent}", "\n")\gsub "%s+$", "") + +{ :unindent } From 01555dc4f4056236a1d7ace42dd8e3a1eca1073e Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 7 Jun 2014 11:09:50 -0700 Subject: [PATCH 211/554] update error rewriters for new @ prefix on chunk name for files --- moonscript/errors.lua | 4 ++-- moonscript/errors.moon | 4 ++-- spec/error_rewriting_spec.moon | 5 ++--- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/moonscript/errors.lua b/moonscript/errors.lua index f8d3254a..bdf5811c 100644 --- a/moonscript/errors.lua +++ b/moonscript/errors.lua @@ -78,8 +78,8 @@ rewrite_traceback = function(text, err) local cache = { } local rewrite_single rewrite_single = function(trace) - local fname, line, msg = trace:match('^%[string "(.-)"]:(%d+): (.*)$') - local tbl = line_tables[fname] + local fname, line, msg = trace:match('^(.-):(%d+): (.*)$') + local tbl = line_tables["@" .. tostring(fname)] if fname and tbl then return concat({ fname, diff --git a/moonscript/errors.moon b/moonscript/errors.moon index a5bd94e8..a6543adb 100644 --- a/moonscript/errors.moon +++ b/moonscript/errors.moon @@ -56,8 +56,8 @@ rewrite_traceback = (text, err) -> cache = {} -- loaded file cache rewrite_single = (trace) -> - fname, line, msg = trace\match '^%[string "(.-)"]:(%d+): (.*)$' - tbl = line_tables[fname] + fname, line, msg = trace\match '^(.-):(%d+): (.*)$' + tbl = line_tables["@#{fname}"] if fname and tbl concat { fname, ":" diff --git a/spec/error_rewriting_spec.moon b/spec/error_rewriting_spec.moon index 6493c654..dfaab1b2 100644 --- a/spec/error_rewriting_spec.moon +++ b/spec/error_rewriting_spec.moon @@ -12,12 +12,11 @@ get_rewritten_line_no = (fname) -> success, err = pcall chunk error "`#{fname}` is supposed to have runtime error!" if success - source = tonumber err\match "]:(%d+)" + source = tonumber err\match "^.-:(%d+):" - line_table = require("moonscript.line_tables")[fname] + line_table = assert require("moonscript.line_tables")["@#{fname}"], "missing line table" errors.reverse_line_number fname, line_table, source, {} - -- TODO: check entire stack trace describe "error rewriting", -> tests = { From 5964d06eeeb0bea086cf85aebe26a818b45f4fbf Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 14 Jun 2014 18:49:22 -0700 Subject: [PATCH 212/554] set posmap for declare on assign for functions --- moonscript/compile.lua | 10 ++++++++-- moonscript/compile.moon | 8 +++++--- moonscript/compile/statement.lua | 2 +- moonscript/compile/statement.moon | 2 +- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/moonscript/compile.lua b/moonscript/compile.lua index ccb2e936..aaa42c29 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -415,8 +415,14 @@ do }) return name end, - add = function(self, item) - self._lines:add(item) + add = function(self, item, pos) + do + local _with_0 = self._lines + _with_0:add(item) + if pos then + _with_0:mark_pos(pos) + end + end return item end, render = function(self, buffer) diff --git a/moonscript/compile.moon b/moonscript/compile.moon index ac6c4638..af700e10 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -288,9 +288,11 @@ class Block @stm {"assign", {name}, {value}} name - -- add a line object - add: (item) => - @_lines\add item + -- add something to the line buffer + add: (item, pos) => + with @_lines + \add item + \mark_pos pos if pos item -- todo: pass in buffer as argument diff --git a/moonscript/compile/statement.lua b/moonscript/compile/statement.lua index 7b6ccb0f..2d2a80c8 100644 --- a/moonscript/compile/statement.lua +++ b/moonscript/compile/statement.lua @@ -78,7 +78,7 @@ return { _with_0:append(declare) else if #undeclared > 0 then - self:add(declare) + self:add(declare, node[-1]) end _with_0:append_list((function() local _accum_0 = { } diff --git a/moonscript/compile/statement.moon b/moonscript/compile/statement.moon index 9d0f43a7..e5c57403 100644 --- a/moonscript/compile/statement.moon +++ b/moonscript/compile/statement.moon @@ -43,7 +43,7 @@ import concat, insert from table if #undeclared == #names and not has_fndef \append declare else - @add declare if #undeclared > 0 + @add declare, node[-1] if #undeclared > 0 \append_list [@value name for name in *names], ", " \append " = " From 68255378781b647db3d6878f89fa8116b84b930f Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 17 Jun 2014 00:03:13 -0700 Subject: [PATCH 213/554] fix indentation --- bin/moonc | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/bin/moonc b/bin/moonc index b273dfdf..a99ae5a6 100755 --- a/bin/moonc +++ b/bin/moonc @@ -180,7 +180,7 @@ function scan_directory(root, collected) collected = collected or {} for fname in lfs.dir(root) do - if not fname:match("^%.") then + if not fname:match("^%.") then local full_path = root..fname if lfs.attributes(full_path, "mode") == "directory" then @@ -285,7 +285,6 @@ function get_sleep_func() return sleep end - function plural(count, word) if count ~= 1 then word = word .. "s" @@ -373,12 +372,12 @@ if opts.w then end for fname in protected do - local target + local target if opts.o then - target = opts.o + target = opts.o else - target = target_dir..convert_path(fname) - end + target = target_dir..convert_path(fname) + end local success, err = compile_and_write(fname, target) if not success then io.stderr:write(table.concat({ @@ -405,12 +404,12 @@ elseif opts.l then end else for _, fname in ipairs(files) do - local target - if opts.o then - target = opts.o - else - target = target_dir..convert_path(fname) - end + local target + if opts.o then + target = opts.o + else + target = target_dir..convert_path(fname) + end local success, err = compile_and_write(fname, target) if not success then io.stderr:write(fname .. "\t" .. err .. "\n") From 6404767dae508789d16ccc3efd49267de96e6463 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 17 Jun 2014 00:33:52 -0700 Subject: [PATCH 214/554] try travis ci --- .travis.yml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..74670737 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,8 @@ +language: c + +install: + - sudo apt-get install luarocks + - sudo luarocks install busted + - sudo luarocks make + +script: busted From 31bab1e099c814fa073d88e4db94923c99bf7f77 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 17 Jun 2014 10:45:42 -0700 Subject: [PATCH 215/554] wip --- bin/moonc | 59 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 16 deletions(-) diff --git a/bin/moonc b/bin/moonc index a99ae5a6..59872059 100755 --- a/bin/moonc +++ b/bin/moonc @@ -9,6 +9,8 @@ local dump_tree = require"moonscript.dump".tree local alt_getopt = require "alt_getopt" local lfs = require "lfs" +local dirsep = package.config:sub(1,1) + local opts, ind = alt_getopt.get_opts(arg, "lvhwt:o:pTXb", { print = "p", tree = "T", version = "v", help = "h", lint = "l" }) @@ -54,11 +56,11 @@ function print_help(err) end function mkdir(path) - local chunks = util.split(path, "/") + local chunks = util.split(path, dirsep) local accum for _, dir in ipairs(chunks) do - accum = accum and accum.."/"..dir or dir + accum = accum and accum.. dirsep ..dir or dir lfs.mkdir(accum) end @@ -66,16 +68,20 @@ function mkdir(path) end function normalize(path) - return path:match("(.-)/*$").."/" + return path:match("^(.-)" .. dirsep .. "*$")..dirsep end function get_dir(fname) - return fname:match("^(.-)[^/]*$") + return fname:match("^(.-)[^" .. dirsep .. "]*$") end -- convert .moon to .lua function convert_path(path) - return (path:gsub("%.moon$", ".lua")) + local new_path = path:gsub("%.moon$", ".lua") + if new_path == path then + new_path = path .. ".lua" + end + return new_path end function log_msg(...) @@ -196,33 +202,49 @@ function scan_directory(root, collected) return collected end -function append(a, b) - for _, v in ipairs(b) do - table.insert(a, v) - end -end - -function remove_dups(tbl) +function remove_dups(tbl, key_fn) local hash = {} local final = {} for _, v in ipairs(tbl) do - if not hash[v] then + local dup_key = key_fn and key_fn(v) or v + if not hash[dup_key] then table.insert(final, v) - hash[v] = true + hash[dup_key] = true end end return final end +-- creates tuples of input and target function get_files(fname, files) files = files or {} if lfs.attributes(fname, "mode") == "directory" then - append(files, scan_directory(fname)) + local head = fname:match("^(.-)[^" .. dirsep .. "]*" .. dirsep .."?$") + for _, sub_fname in ipairs(scan_directory(fname)) do + local target_fname = convert_path(sub_fname) + if opts.t then + if head then + local start, stop = target_fname:find(head, 1, true) + if start == 1 then + target_fname = target_fname:sub(stop + 1) + end + end + + target_fname = normalize(opts.t) .. target_fname + end + + table.insert(files, {sub_fname, target_fname}) + end else - table.insert(files, "./"..fname) + local target_fname = convert_path(fname) + if opts.t then + target_fname = normalize(opts.t) .. target_fname + end + + table.insert(files, {fname, target_fname}) end return files @@ -268,8 +290,13 @@ for _, input in ipairs(inputs) do get_files(input, files) end +require("moon").p(files) + +do return end + files = remove_dups(files) + function get_sleep_func() local sleep if not pcall(function() From a4585f8b1c9860856218c649e66e5077f0728b80 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 17 Jun 2014 20:27:10 -0700 Subject: [PATCH 216/554] finish converting moonc to have better directory support, remove -t from watch mode temporarily --- bin/moonc | 99 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 54 insertions(+), 45 deletions(-) diff --git a/bin/moonc b/bin/moonc index 59872059..bb9c0d0d 100755 --- a/bin/moonc +++ b/bin/moonc @@ -71,10 +71,15 @@ function normalize(path) return path:match("^(.-)" .. dirsep .. "*$")..dirsep end -function get_dir(fname) +function parse_dir(fname) return fname:match("^(.-)[^" .. dirsep .. "]*$") end +function parse_file(fname) + return fname:match("^.-([^" .. dirsep .. "]*)$") +end + + -- convert .moon to .lua function convert_path(path) local new_path = path:gsub("%.moon$", ".lua") @@ -111,7 +116,7 @@ function write_file(fname, code) if opts.p then if code ~= "" then print(code) end else - mkdir(get_dir(fname)) + mkdir(parse_dir(fname)) local out_f = io.open(fname, "w") if not out_f then return nil, "Failed to write output: "..fname @@ -217,6 +222,15 @@ function remove_dups(tbl, key_fn) return final end +local function is_abs_path(path) + local first = path:sub(1, 1) + if dirsep == "\\" then + return first == "/" or first == "\\" or path:sub(2,1) == ":" + else + return first == dirsep + end +end + -- creates tuples of input and target function get_files(fname, files) files = files or {} @@ -241,7 +255,12 @@ function get_files(fname, files) else local target_fname = convert_path(fname) if opts.t then - target_fname = normalize(opts.t) .. target_fname + local prefix = normalize(opts.t) + + if is_abs_path(target_fname) then + target_fname = parse_file(target_fname) + end + target_fname = prefix .. target_fname end table.insert(files, {fname, target_fname}) @@ -275,27 +294,14 @@ if #inputs == 0 then print_help("No files specified") end -local target_dir = "." -if opts.t then - if mkdir(opts.t) ~= "directory" then - print_help("Invalid target dir") - end - target_dir = opts.t -end - -target_dir = target_dir.."/" - local files = {} for _, input in ipairs(inputs) do get_files(input, files) end -require("moon").p(files) - -do return end - -files = remove_dups(files) - +files = remove_dups(files, function(f) + return f[2] +end) function get_sleep_func() local sleep @@ -330,9 +336,15 @@ function create_watcher(files) if inotify then local dirs = {} - for _, fname in ipairs(files) do - table.insert(dirs, get_dir(fname)) + + for _, tuple in ipairs(files) do + local dir = parse_dir(tuple[1]) + if dir == "" then + dir = "./" + end + table.insert(dirs, dir) end + dirs = remove_dups(dirs) return coroutine.wrap(function() @@ -347,15 +359,20 @@ function create_watcher(files) while true do local events = handle:read() - if events then - for _, ev in ipairs(events) do - local fname = wd_table[ev.wd]..ev.name - if fname:match("%.moon$") then - coroutine.yield(fname) + if not events then + break + end + + for _, ev in ipairs(events) do + local fname = ev.name + if fname:match("%.moon$") then + local dir = wd_table[ev.wd] + if dir ~= "./" then + fname = dir .. fname end + -- TODO: check to make sure the file was in the original set + coroutine.yield(fname) end - else - break end end end) @@ -367,7 +384,8 @@ function create_watcher(files) local mod_time = {} while true do - for _, file in ipairs(files) do + for _, tuple in ipairs(files) do + local file = tuple[1] local time = lfs.attributes(file, "modification") if not mod_time[file] then mod_time[file] = time @@ -390,7 +408,7 @@ if opts.w then local watcher = create_watcher(files) -- catches interrupt error for ctl-c local protected = function() - local status, file = pcall(watcher) + local status, file = true, watcher() if status then return file elseif file ~= "interrupted!" then @@ -399,12 +417,7 @@ if opts.w then end for fname in protected do - local target - if opts.o then - target = opts.o - else - target = target_dir..convert_path(fname) - end + local target = convert_path(fname) local success, err = compile_and_write(fname, target) if not success then io.stderr:write(table.concat({ @@ -420,7 +433,8 @@ if opts.w then io.stderr:write("\nQuitting...\n") elseif opts.l then - for _, fname in pairs(files) do + for _, tuple in pairs(files) do + local fname = tuple[1] lint = require "moonscript.cmd.lint" local res, err = lint.lint_file(fname) if res then @@ -430,19 +444,14 @@ elseif opts.l then end end else - for _, fname in ipairs(files) do - local target - if opts.o then - target = opts.o - else - target = target_dir..convert_path(fname) - end + for _, tuple in ipairs(files) do + local fname, target = unpack(tuple) local success, err = compile_and_write(fname, target) if not success then io.stderr:write(fname .. "\t" .. err .. "\n") os.exit(1) else - log_msg("Built", fname) + log_msg("Built", fname, "->", target) end end end From c60d83c54697328e714fa974fbf46e674a6673cc Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 18 Jun 2014 09:23:41 -0700 Subject: [PATCH 217/554] start moving moonc code to moonscript --- bin/moonc | 128 ++++++++---------------------------- moonscript-dev-1.rockspec | 1 + moonscript/cmd/moonc.lua | 134 ++++++++++++++++++++++++++++++++++++++ moonscript/cmd/moonc.moon | 122 ++++++++++++++++++++++++++++++++++ spec/cmd_spec.moon | 68 +++++++++++++++++++ 5 files changed, 351 insertions(+), 102 deletions(-) create mode 100644 moonscript/cmd/moonc.lua create mode 100644 moonscript/cmd/moonc.moon create mode 100644 spec/cmd_spec.moon diff --git a/bin/moonc b/bin/moonc index bb9c0d0d..f5b11842 100755 --- a/bin/moonc +++ b/bin/moonc @@ -55,62 +55,19 @@ function print_help(err) end end -function mkdir(path) - local chunks = util.split(path, dirsep) - local accum - - for _, dir in ipairs(chunks) do - accum = accum and accum.. dirsep ..dir or dir - lfs.mkdir(accum) - end - - return lfs.attributes(path, "mode") -end - -function normalize(path) - return path:match("^(.-)" .. dirsep .. "*$")..dirsep -end - -function parse_dir(fname) - return fname:match("^(.-)[^" .. dirsep .. "]*$") -end - -function parse_file(fname) - return fname:match("^.-([^" .. dirsep .. "]*)$") -end - - --- convert .moon to .lua -function convert_path(path) - local new_path = path:gsub("%.moon$", ".lua") - if new_path == path then - new_path = path .. ".lua" - end - return new_path -end - function log_msg(...) if not opts.p then io.stderr:write(table.concat({...}, " ") .. "\n") end end -local gettime = nil -if opts.b then - pcall(function() - require "socket" - gettime = socket.gettime - end) - - function format_time(time) - return ("%.3fms"):format(time*1000) - end - if not gettime then - print_help"LuaSocket needed for benchmark" - end -else - gettime = function() return 0 end -end +local moonc = require("moonscript.cmd.moonc") +local mkdir = moonc.mkdir +local normalize_dir = moonc.normalize_dir +local parse_dir = moonc.parse_dir +local parse_file = moonc.parse_file +local convert_path = moonc.convert_path +local compile_file_text = moonc.compile_file_text function write_file(fname, code) if opts.p then @@ -125,50 +82,8 @@ function write_file(fname, code) out_f:write(code.."\n") out_f:close() end - return true -end - -function compile_file(text, fname) - local parse_time = gettime() - local tree, err = parse.string(text) - parse_time = gettime() - parse_time - - if not tree then - return nil, err - end - - if opts.T then - opts.p = true - dump_tree(tree) - return "" - else - local compile_time = gettime() - local code, posmap_or_err, err_pos = compile.tree(tree) - compile_time = gettime() - compile_time - - if not code then - return nil, compile.format_error(posmap_or_err, err_pos, text) - end - if opts.X then - opts.p = true - print("Pos", "Lua", ">>", "Moon") - print(util.debug_posmap(posmap_or_err, text, code)) - return "" - end - - if opts.b then - opts.p = true - return table.concat({ - fname, - "Parse time \t" .. format_time(parse_time), - "Compile time\t" .. format_time(compile_time), - "" - }, "\n") - end - - return code - end + return "built" end function compile_and_write(from, to) @@ -178,16 +93,25 @@ function compile_and_write(from, to) end local text = f:read("*a") - local code, err = compile_file(text, from) - if not code then + local code, err = compile_file_text(text, from, { + benchmark = opts.b, + show_posmap = opts.X, + show_parse_tree = opts.T, + }) + + if not code and err then return nil, err end + if not code then + return true + end + return write_file(to, code) end function scan_directory(root, collected) - root = normalize(root) + root = normalize_dir(root) collected = collected or {} for fname in lfs.dir(root) do @@ -247,7 +171,7 @@ function get_files(fname, files) end end - target_fname = normalize(opts.t) .. target_fname + target_fname = normalize_dir(opts.t) .. target_fname end table.insert(files, {sub_fname, target_fname}) @@ -255,7 +179,7 @@ function get_files(fname, files) else local target_fname = convert_path(fname) if opts.t then - local prefix = normalize(opts.t) + local prefix = normalize_dir(opts.t) if is_abs_path(target_fname) then target_fname = parse_file(target_fname) @@ -426,8 +350,8 @@ if opts.w then err, "\n", }, "\n")) - else - log_msg("Built:", fname, "->", target) + elseif success == "build" then + log_msg("Built", fname, "->", target) end end @@ -450,8 +374,8 @@ else if not success then io.stderr:write(fname .. "\t" .. err .. "\n") os.exit(1) - else - log_msg("Built", fname, "->", target) + elseif success == "build" then + log_msg("Built", fname) end end end diff --git a/moonscript-dev-1.rockspec b/moonscript-dev-1.rockspec index 7fd5ef17..f1b4a1c5 100644 --- a/moonscript-dev-1.rockspec +++ b/moonscript-dev-1.rockspec @@ -28,6 +28,7 @@ build = { ["moonscript.base"] = "moonscript/base.lua", ["moonscript.cmd.coverage"] = "moonscript/cmd/coverage.lua", ["moonscript.cmd.lint"] = "moonscript/cmd/lint.lua", + ["moonscript.cmd.moonc"] = "moonscript/cmd/moonc.lua", ["moonscript.compile"] = "moonscript/compile.lua", ["moonscript.compile.statement"] = "moonscript/compile/statement.lua", ["moonscript.compile.value"] = "moonscript/compile/value.lua", diff --git a/moonscript/cmd/moonc.lua b/moonscript/cmd/moonc.lua new file mode 100644 index 00000000..642e68c4 --- /dev/null +++ b/moonscript/cmd/moonc.lua @@ -0,0 +1,134 @@ +local lfs = require("lfs") +local split +do + local _obj_0 = require("moonscript.util") + split = _obj_0.split +end +local dirsep = package.config:sub(1, 1) +local dirsep_chars +if dirsep == "\\" then + dirsep_chars = "\\/" +else + dirsep_chars = dirsep +end +local mkdir +mkdir = function(path) + local chunks = split(path, dirsep) + local accum + for _index_0 = 1, #chunks do + local dir = chunks[_index_0] + accum = accum and tostring(accum) .. tostring(dirsep) .. tostring(dir) or dir + lfs.mkdir(accum) + end + return lfs.attributes(path, "mode") +end +local normalize_dir +normalize_dir = function(path) + return path:match("^(.-)[" .. tostring(dirsep_chars) .. "]*$") .. dirsep +end +local parse_dir +parse_dir = function(path) + return (path:match("^(.-)[^" .. tostring(dirsep_chars) .. "]*$")) +end +local parse_file +parse_file = function(path) + return (path:match("^.-([^" .. tostring(dirsep_chars) .. "]*)$")) +end +local convert_path +convert_path = function(path) + local new_path = path:gsub("%.moon$", ".lua") + if new_path == path then + new_path = path .. ".lua" + end + return new_path +end +local format_time +format_time = function(time) + return ("%.3fms"):format(time * 1000) +end +local gettime +do + local socket + gettime = function() + if socket == nil then + pcall(function() + socket = require("socket") + end) + if not (socket) then + socket = false + end + end + if socket then + return socket.gettime() + else + return nil, "LuaSocket needed for benchmark" + end + end +end +local compile_file_text +compile_file_text = function(text, fname, opts) + if opts == nil then + opts = { } + end + local parse = require("moonscript.parse") + local compile = require("moonscript.compile") + local parse_time + if opts.benchmark then + parse_time = assert(gettime()) + end + local tree, err = parse.string(text) + if not (tree) then + return nil, err + end + if parse_time then + parse_time = gettime() - parse_time + end + if opts.show_parse_tree then + local dump = require("moonscript.dump") + dump.tree(tree) + return nil + end + local compile_time + if opts.benchmark then + compile_time = gettime() + end + local code, posmap_or_err, err_pos = compile.tree(tree) + if not (code) then + return nil, compile.format_error(posmap_or_err, err_pos, text) + end + if compile_time then + compile_time = gettime() - compile_time + end + if opts.show_posmap then + local debug_posmap + do + local _obj_0 = require("moonscript.util") + debug_posmap = _obj_0.debug_posmap + end + print("Pos", "Lua", ">>", "Moon") + print(debug_posmap(posmap_or_err, text, code)) + return nil + end + if opts.benchmark then + print(table.concat({ + fname, + "Parse time \t" .. format_time(parse_time), + "Compile time\t" .. format_time(compile_time), + "" + }, "\n")) + return nil + end + return code +end +return { + dirsep = dirsep, + mkdir = mkdir, + normalize_dir = normalize_dir, + parse_dir = parse_dir, + parse_file = parse_file, + new_path = new_path, + convert_path = convert_path, + gettime = gettime, + format_time = format_time, + compile_file_text = compile_file_text +} diff --git a/moonscript/cmd/moonc.moon b/moonscript/cmd/moonc.moon new file mode 100644 index 00000000..79cefe1c --- /dev/null +++ b/moonscript/cmd/moonc.moon @@ -0,0 +1,122 @@ +-- assorted utilities for moonc command line tool + +lfs = require "lfs" + +import split from require "moonscript.util" + +dirsep = package.config\sub 1,1 +dirsep_chars = if dirsep == "\\" + "\\/" -- windows +else + dirsep + + +-- similar to mkdir -p +mkdir = (path) -> + chunks = split path, dirsep + + local accum + for dir in *chunks + accum = accum and "#{accum}#{dirsep}#{dir}" or dir + lfs.mkdir accum + + lfs.attributes path, "mode" + +-- strips excess / and ensures path ends with / +normalize_dir = (path) -> + path\match("^(.-)[#{dirsep_chars}]*$") .. dirsep + +-- parse the directory out of a path +parse_dir = (path) -> + (path\match "^(.-)[^#{dirsep_chars}]*$") + +-- parse the filename out of a path +parse_file = (path) -> + (path\match "^.-([^#{dirsep_chars}]*)$") + +-- converts .moon to a .lua path for calcuating compile target +convert_path = (path) -> + new_path = path\gsub "%.moon$", ".lua" + if new_path == path + new_path = path .. ".lua" + new_path + +format_time = (time) -> + "%.3fms"\format time*1000 + +gettime = do + local socket + -> + if socket == nil + pcall -> + socket = require "socket" + + unless socket + socket = false + + if socket + socket.gettime() + else + nil, "LuaSocket needed for benchmark" + +-- compiles file to lua +-- returns nil, error on error +-- returns just nil if some option handled the output instead +compile_file_text = (text, fname, opts={}) -> + parse = require "moonscript.parse" + compile = require "moonscript.compile" + + parse_time = if opts.benchmark + assert gettime! + + tree, err = parse.string text + return nil, err unless tree + + if parse_time + parse_time = gettime! - parse_time + + if opts.show_parse_tree + dump = require "moonscript.dump" + dump.tree tree + return nil + + compile_time = if opts.benchmark + gettime! + + code, posmap_or_err, err_pos = compile.tree tree + + unless code + return nil, compile.format_error posmap_or_err, err_pos, text + + if compile_time + compile_time = gettime() - compile_time + + if opts.show_posmap + import debug_posmap from require "moonscript.util" + print "Pos", "Lua", ">>", "Moon" + print debug_posmap posmap_or_err, text, code + return nil + + if opts.benchmark + print table.concat { + fname, + "Parse time \t" .. format_time(parse_time), + "Compile time\t" .. format_time(compile_time), + "" + }, "\n" + return nil + + code + +{ + :dirsep + :mkdir + :normalize_dir + :parse_dir + :parse_file + :new_path + :convert_path + :gettime + :format_time + :compile_file_text +} diff --git a/spec/cmd_spec.moon b/spec/cmd_spec.moon new file mode 100644 index 00000000..cee4bbee --- /dev/null +++ b/spec/cmd_spec.moon @@ -0,0 +1,68 @@ + +moonc = require "moonscript.cmd.moonc" + +-- TODO: add specs for windows equivalents + +describe "moonc", -> + same = (fn, a, b)-> + assert.same b, fn a + + it "should normalize dir", -> + same moonc.normalize_dir, "hello/world/", "hello/world/" + same moonc.normalize_dir, "hello/world//", "hello/world/" + same moonc.normalize_dir, "", "/" -- wrong + same moonc.normalize_dir, "hello", "hello/" + + + it "should parse dir", -> + same moonc.parse_dir, "/hello/world/file", "/hello/world/" + same moonc.parse_dir, "/hello/world/", "/hello/world/" + same moonc.parse_dir, "world", "" + same moonc.parse_dir, "", "" + + it "should parse file", -> + same moonc.parse_file, "/hello/world/file", "file" + same moonc.parse_file, "/hello/world/", "" + same moonc.parse_file, "world", "world" + same moonc.parse_file, "", "" + + it "convert path", -> + same moonc.convert_path, "test.moon", "test.lua" + same moonc.convert_path, "/hello/file.moon", "/hello/file.lua" + same moonc.convert_path, "/hello/world/file", "/hello/world/file.lua" + + it "chould compile file text", -> + assert.same { + [[return print('hello')]] + }, { + moonc.compile_file_text "print'hello'", "test.moon" + } + + describe "stubbed lfs", -> + local dirs + + before_each -> + dirs = {} + package.loaded.lfs = nil + package.loaded["moonscript.cmd.moonc"] = nil + + package.loaded.lfs = { + mkdir: (dir) -> table.insert dirs, dir + attributes: -> "directory" + } + + moonc = require "moonscript.cmd.moonc" + + after_each -> + package.loaded.lfs = nil + package.loaded["moonscript.cmd.moonc"] = nil + moonc = require "moonscript.cmd.moonc" + + it "should make directory", -> + moonc.mkdir "hello/world/directory" + assert.same { + "hello" + "hello/world" + "hello/world/directory" + }, dirs + From a4e03813fc552fe55f7525d86c8ca1cb32bad44a Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 18 Jun 2014 09:48:25 -0700 Subject: [PATCH 218/554] more moonc functions to module --- bin/moonc | 55 +++++---------------------------------- moonscript/cmd/moonc.lua | 53 ++++++++++++++++++++++++++++--------- moonscript/cmd/moonc.moon | 46 ++++++++++++++++++++++++++++---- spec/cmd_spec.moon | 2 +- 4 files changed, 89 insertions(+), 67 deletions(-) diff --git a/bin/moonc b/bin/moonc index f5b11842..13a8ef0d 100755 --- a/bin/moonc +++ b/bin/moonc @@ -67,50 +67,9 @@ local normalize_dir = moonc.normalize_dir local parse_dir = moonc.parse_dir local parse_file = moonc.parse_file local convert_path = moonc.convert_path -local compile_file_text = moonc.compile_file_text +local compile_and_write = moonc.compile_and_write -function write_file(fname, code) - if opts.p then - if code ~= "" then print(code) end - else - mkdir(parse_dir(fname)) - local out_f = io.open(fname, "w") - if not out_f then - return nil, "Failed to write output: "..fname - end - - out_f:write(code.."\n") - out_f:close() - end - - return "built" -end - -function compile_and_write(from, to) - local f = io.open(from) - if not f then - return nil, "Can't find file" - end - local text = f:read("*a") - - local code, err = compile_file_text(text, from, { - benchmark = opts.b, - show_posmap = opts.X, - show_parse_tree = opts.T, - }) - - if not code and err then - return nil, err - end - - if not code then - return true - end - - return write_file(to, code) -end - -function scan_directory(root, collected) +local function scan_directory(root, collected) root = normalize_dir(root) collected = collected or {} @@ -131,7 +90,7 @@ function scan_directory(root, collected) return collected end -function remove_dups(tbl, key_fn) +local function remove_dups(tbl, key_fn) local hash = {} local final = {} @@ -156,7 +115,7 @@ local function is_abs_path(path) end -- creates tuples of input and target -function get_files(fname, files) +local function get_files(fname, files) files = files or {} if lfs.attributes(fname, "mode") == "directory" then @@ -227,7 +186,7 @@ files = remove_dups(files, function(f) return f[2] end) -function get_sleep_func() +local function get_sleep_func() local sleep if not pcall(function() require "socket" @@ -242,7 +201,7 @@ function get_sleep_func() return sleep end -function plural(count, word) +local function plural(count, word) if count ~= 1 then word = word .. "s" end @@ -250,7 +209,7 @@ function plural(count, word) end -- returns an iterator that returns files that have been updated -function create_watcher(files) +local function create_watcher(files) local msg = "Starting watch loop (Ctrl-C to exit)" local inotify diff --git a/moonscript/cmd/moonc.lua b/moonscript/cmd/moonc.lua index 642e68c4..d793b329 100644 --- a/moonscript/cmd/moonc.lua +++ b/moonscript/cmd/moonc.lua @@ -4,14 +4,13 @@ do local _obj_0 = require("moonscript.util") split = _obj_0.split end -local dirsep = package.config:sub(1, 1) -local dirsep_chars +local dirsep, dirsep_chars, mkdir, normalize_dir, parse_dir, parse_file, convert_path, format_time, gettime, compile_file_text, write_file, compile_and_write +dirsep = package.config:sub(1, 1) if dirsep == "\\" then dirsep_chars = "\\/" else dirsep_chars = dirsep end -local mkdir mkdir = function(path) local chunks = split(path, dirsep) local accum @@ -22,19 +21,15 @@ mkdir = function(path) end return lfs.attributes(path, "mode") end -local normalize_dir normalize_dir = function(path) return path:match("^(.-)[" .. tostring(dirsep_chars) .. "]*$") .. dirsep end -local parse_dir parse_dir = function(path) return (path:match("^(.-)[^" .. tostring(dirsep_chars) .. "]*$")) end -local parse_file parse_file = function(path) return (path:match("^.-([^" .. tostring(dirsep_chars) .. "]*)$")) end -local convert_path convert_path = function(path) local new_path = path:gsub("%.moon$", ".lua") if new_path == path then @@ -42,11 +37,9 @@ convert_path = function(path) end return new_path end -local format_time format_time = function(time) return ("%.3fms"):format(time * 1000) end -local gettime do local socket gettime = function() @@ -65,7 +58,6 @@ do end end end -local compile_file_text compile_file_text = function(text, fname, opts) if opts == nil then opts = { } @@ -86,7 +78,7 @@ compile_file_text = function(text, fname, opts) if opts.show_parse_tree then local dump = require("moonscript.dump") dump.tree(tree) - return nil + return true end local compile_time if opts.benchmark then @@ -107,7 +99,7 @@ compile_file_text = function(text, fname, opts) end print("Pos", "Lua", ">>", "Moon") print(debug_posmap(posmap_or_err, text, code)) - return nil + return true end if opts.benchmark then print(table.concat({ @@ -120,6 +112,40 @@ compile_file_text = function(text, fname, opts) end return code end +write_file = function(fname, code) + mkdir(parse_dir(fname)) + local f, err = io.open(fname, "w") + if not (f) then + return nil, err + end + assert(f:write(code)) + assert(f:write("\n")) + f:close() + return "build" +end +compile_and_write = function(src, dest, opts) + if opts == nil then + opts = { } + end + local f = io.open(src) + if not (f) then + return nil, "Can't find file" + end + local text = assert(f:read("*a")) + f:close() + local code, err = compile_file_text(text, opts) + if not code then + return nil, err + end + if code == true then + return true + end + if opts.print then + print(text) + return true + end + return write_file(dest, code) +end return { dirsep = dirsep, mkdir = mkdir, @@ -130,5 +156,6 @@ return { convert_path = convert_path, gettime = gettime, format_time = format_time, - compile_file_text = compile_file_text + compile_file_text = compile_file_text, + compile_and_write = compile_and_write } diff --git a/moonscript/cmd/moonc.moon b/moonscript/cmd/moonc.moon index 79cefe1c..3bb5716f 100644 --- a/moonscript/cmd/moonc.moon +++ b/moonscript/cmd/moonc.moon @@ -4,13 +4,14 @@ lfs = require "lfs" import split from require "moonscript.util" +local * + dirsep = package.config\sub 1,1 dirsep_chars = if dirsep == "\\" "\\/" -- windows else dirsep - -- similar to mkdir -p mkdir = (path) -> chunks = split path, dirsep @@ -59,9 +60,9 @@ gettime = do else nil, "LuaSocket needed for benchmark" --- compiles file to lua +-- compiles file to lua, returns lua code -- returns nil, error on error --- returns just nil if some option handled the output instead +-- returns true if some option handled the output instead compile_file_text = (text, fname, opts={}) -> parse = require "moonscript.parse" compile = require "moonscript.compile" @@ -78,7 +79,7 @@ compile_file_text = (text, fname, opts={}) -> if opts.show_parse_tree dump = require "moonscript.dump" dump.tree tree - return nil + return true compile_time = if opts.benchmark gettime! @@ -95,7 +96,7 @@ compile_file_text = (text, fname, opts={}) -> import debug_posmap from require "moonscript.util" print "Pos", "Lua", ">>", "Moon" print debug_posmap posmap_or_err, text, code - return nil + return true if opts.benchmark print table.concat { @@ -108,6 +109,39 @@ compile_file_text = (text, fname, opts={}) -> code +write_file = (fname, code) -> + mkdir parse_dir fname + f, err = io.open fname, "w" + unless f + return nil, err + + assert f\write code + assert f\write "\n" + f\close! + "build" + +compile_and_write = (src, dest, opts={}) -> + f = io.open src + unless f + return nil, "Can't find file" + + text = assert f\read("*a") + f\close! + + code, err = compile_file_text text, opts + + if not code + return nil, err + + if code == true + return true + + if opts.print + print text + return true + + write_file dest, code + { :dirsep :mkdir @@ -118,5 +152,7 @@ compile_file_text = (text, fname, opts={}) -> :convert_path :gettime :format_time + :compile_file_text + :compile_and_write } diff --git a/spec/cmd_spec.moon b/spec/cmd_spec.moon index cee4bbee..30e3deee 100644 --- a/spec/cmd_spec.moon +++ b/spec/cmd_spec.moon @@ -31,7 +31,7 @@ describe "moonc", -> same moonc.convert_path, "/hello/file.moon", "/hello/file.lua" same moonc.convert_path, "/hello/world/file", "/hello/world/file.lua" - it "chould compile file text", -> + it "should compile file text", -> assert.same { [[return print('hello')]] }, { From 5904373ab81c7881c7a3fc97c694865a8871e11e Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 18 Jun 2014 10:14:26 -0700 Subject: [PATCH 219/554] path_to_target --- bin/moonc | 43 ++++++++------------------------------- moonscript/cmd/moonc.lua | 39 ++++++++++++++++++++++++++++++++++- moonscript/cmd/moonc.moon | 35 +++++++++++++++++++++++++++++++ spec/cmd_spec.moon | 20 ++++++++++++++++++ 4 files changed, 102 insertions(+), 35 deletions(-) diff --git a/bin/moonc b/bin/moonc index 13a8ef0d..3a3ae021 100755 --- a/bin/moonc +++ b/bin/moonc @@ -68,6 +68,7 @@ local parse_dir = moonc.parse_dir local parse_file = moonc.parse_file local convert_path = moonc.convert_path local compile_and_write = moonc.compile_and_write +local path_to_target = moonc.path_to_target local function scan_directory(root, collected) root = normalize_dir(root) @@ -105,48 +106,22 @@ local function remove_dups(tbl, key_fn) return final end -local function is_abs_path(path) - local first = path:sub(1, 1) - if dirsep == "\\" then - return first == "/" or first == "\\" or path:sub(2,1) == ":" - else - return first == dirsep - end -end - -- creates tuples of input and target local function get_files(fname, files) files = files or {} if lfs.attributes(fname, "mode") == "directory" then - local head = fname:match("^(.-)[^" .. dirsep .. "]*" .. dirsep .."?$") for _, sub_fname in ipairs(scan_directory(fname)) do - local target_fname = convert_path(sub_fname) - if opts.t then - if head then - local start, stop = target_fname:find(head, 1, true) - if start == 1 then - target_fname = target_fname:sub(stop + 1) - end - end - - target_fname = normalize_dir(opts.t) .. target_fname - end - - table.insert(files, {sub_fname, target_fname}) + table.insert(files, { + sub_fname, + path_to_target(sub_fname, opts.t, fname) + }) end else - local target_fname = convert_path(fname) - if opts.t then - local prefix = normalize_dir(opts.t) - - if is_abs_path(target_fname) then - target_fname = parse_file(target_fname) - end - target_fname = prefix .. target_fname - end - - table.insert(files, {fname, target_fname}) + table.insert(files, { + fname, + path_to_target(fname, opts.t) + }) end return files diff --git a/moonscript/cmd/moonc.lua b/moonscript/cmd/moonc.lua index d793b329..55009c9b 100644 --- a/moonscript/cmd/moonc.lua +++ b/moonscript/cmd/moonc.lua @@ -4,7 +4,7 @@ do local _obj_0 = require("moonscript.util") split = _obj_0.split end -local dirsep, dirsep_chars, mkdir, normalize_dir, parse_dir, parse_file, convert_path, format_time, gettime, compile_file_text, write_file, compile_and_write +local dirsep, dirsep_chars, mkdir, normalize_dir, parse_dir, parse_file, convert_path, format_time, gettime, compile_file_text, write_file, compile_and_write, is_abs_path, path_to_target dirsep = package.config:sub(1, 1) if dirsep == "\\" then dirsep_chars = "\\/" @@ -146,6 +146,42 @@ compile_and_write = function(src, dest, opts) end return write_file(dest, code) end +is_abs_path = function(path) + local first = path:sub(1, 1) + if dirsep == "\\" then + return first == "/" or first == "\\" or path:sub(2, 1) == ":" + else + return first == dirsep + end +end +path_to_target = function(path, target_dir, base_dir) + if target_dir == nil then + target_dir = nil + end + if base_dir == nil then + base_dir = nil + end + local target = convert_path(path) + if target_dir then + target_dir = normalize_dir(target_dir) + end + if base_dir and target_dir then + local head = base_dir:match("^(.-)[^" .. tostring(dirsep_chars) .. "]*[" .. tostring(dirsep_chars) .. "]?$") + if head then + local start, stop = target:find(head, 1, true) + if start == 1 then + target = target:sub(stop + 1) + end + end + end + if target_dir then + if is_abs_path(target) then + target = parse_file(target) + end + target = target_dir .. target + end + return target +end return { dirsep = dirsep, mkdir = mkdir, @@ -156,6 +192,7 @@ return { convert_path = convert_path, gettime = gettime, format_time = format_time, + path_to_target = path_to_target, compile_file_text = compile_file_text, compile_and_write = compile_and_write } diff --git a/moonscript/cmd/moonc.moon b/moonscript/cmd/moonc.moon index 3bb5716f..8cb2bbb2 100644 --- a/moonscript/cmd/moonc.moon +++ b/moonscript/cmd/moonc.moon @@ -142,6 +142,40 @@ compile_and_write = (src, dest, opts={}) -> write_file dest, code +is_abs_path = (path) -> + first = path\sub 1, 1 + if dirsep == "\\" + first == "/" or first == "\\" or path\sub(2,1) == ":" + else + first == dirsep + + +-- calcuate where a path should be compiled to +-- target_dir: the directory to place the file (optional, from -t flag) +-- base_dir: the directory where the file came from when globbing recursively +path_to_target = (path, target_dir=nil, base_dir=nil) -> + target = convert_path path + + if target_dir + target_dir = normalize_dir target_dir + + if base_dir and target_dir + -- one directory back + head = base_dir\match("^(.-)[^#{dirsep_chars}]*[#{dirsep_chars}]?$") + + if head + start, stop = target\find head, 1, true + if start == 1 + target = target\sub(stop + 1) + + if target_dir + if is_abs_path target + target = parse_file target + + target = target_dir .. target + + target + { :dirsep :mkdir @@ -152,6 +186,7 @@ compile_and_write = (src, dest, opts={}) -> :convert_path :gettime :format_time + :path_to_target :compile_file_text :compile_and_write diff --git a/spec/cmd_spec.moon b/spec/cmd_spec.moon index 30e3deee..3ac5dea0 100644 --- a/spec/cmd_spec.moon +++ b/spec/cmd_spec.moon @@ -31,6 +31,26 @@ describe "moonc", -> same moonc.convert_path, "/hello/file.moon", "/hello/file.lua" same moonc.convert_path, "/hello/world/file", "/hello/world/file.lua" + it "calculate target", -> + p = moonc.path_to_target + + assert.same "test.lua", p "test.moon" + assert.same "hello/world.lua", p "hello/world.moon" + assert.same "compiled/test.lua", p "test.moon", "compiled" + + assert.same "/home/leafo/test.lua", p "/home/leafo/test.moon" + assert.same "compiled/test.lua", p "/home/leafo/test.moon", "compiled" + assert.same "/compiled/test.lua", p "/home/leafo/test.moon", "/compiled/" + + assert.same "moonscript/hello.lua", p "moonscript/hello.moon", nil, "moonscript" + assert.same "out/moonscript/hello.lua", p "moonscript/hello.moon", "out", "moonscript" + + assert.same "out/moonscript/package/hello.lua", + p "moonscript/package/hello.moon", "out", "moonscript/" + + assert.same "/out/moonscript/package/hello.lua", + p "/home/leafo/moonscript/package/hello.moon", "/out", "/home/leafo/moonscript" + it "should compile file text", -> assert.same { [[return print('hello')]] From 6cdfca6ab2befa335eba65de5101a54bf03a193d Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 18 Jun 2014 10:26:20 -0700 Subject: [PATCH 220/554] clean up moonc --- bin/moonc | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/bin/moonc b/bin/moonc index 3a3ae021..d68302a9 100755 --- a/bin/moonc +++ b/bin/moonc @@ -1,16 +1,8 @@ #!/usr/bin/env lua -local parse = require "moonscript.parse" -local compile = require "moonscript.compile" -local util = require "moonscript.util" - -local dump_tree = require"moonscript.dump".tree - local alt_getopt = require "alt_getopt" local lfs = require "lfs" -local dirsep = package.config:sub(1,1) - local opts, ind = alt_getopt.get_opts(arg, "lvhwt:o:pTXb", { print = "p", tree = "T", version = "v", help = "h", lint = "l" }) @@ -113,15 +105,15 @@ local function get_files(fname, files) if lfs.attributes(fname, "mode") == "directory" then for _, sub_fname in ipairs(scan_directory(fname)) do table.insert(files, { - sub_fname, - path_to_target(sub_fname, opts.t, fname) - }) + sub_fname, + path_to_target(sub_fname, opts.t, fname) + }) end else table.insert(files, { - fname, - path_to_target(fname, opts.t) - }) + fname, + path_to_target(fname, opts.t) + }) end return files @@ -130,8 +122,12 @@ end if opts.h then print_help() end if read_stdin then + local parse = require "moonscript.parse" + local compile = require "moonscript.compile" + local text = io.stdin:read("*a") local tree, err = parse.string(text) + if not tree then error(err) end local code, err, pos = compile.tree(tree) @@ -158,7 +154,7 @@ for _, input in ipairs(inputs) do end files = remove_dups(files, function(f) - return f[2] + return f[2] end) local function get_sleep_func() @@ -293,7 +289,7 @@ if opts.w then elseif opts.l then for _, tuple in pairs(files) do local fname = tuple[1] - lint = require "moonscript.cmd.lint" + local lint = require "moonscript.cmd.lint" local res, err = lint.lint_file(fname) if res then io.stderr:write(res .. "\n\n") From fec4114adcca82e451e7611efbeafa903aaf3ddd Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 18 Jun 2014 23:45:47 -0700 Subject: [PATCH 221/554] split apart docs into more pages, add some more content --- docs/api.md | 131 +++++++++++++++++ docs/command_line.md | 250 +++++++++++++++++++++++++++++++ docs/reference.md | 343 +------------------------------------------ docs/standard_lib.md | 8 +- 4 files changed, 392 insertions(+), 340 deletions(-) create mode 100644 docs/api.md create mode 100644 docs/command_line.md diff --git a/docs/api.md b/docs/api.md new file mode 100644 index 00000000..367891af --- /dev/null +++ b/docs/api.md @@ -0,0 +1,131 @@ +target: reference/api +template: reference +title: Compiler API +short_name: api +-- + +# MoonScript Compiler API + +## Autocompiling with the `moonscript` Module + +After installing MoonScript, you can include the `moonscript` module to make +any Lua script MoonScript aware. + +```lua +require "moonscript" +``` + +After `moonscript` is required, Lua's package loader is updated to search for +`.moon` files on any subsequent calls to `require`. The search path for `.moon` +files is based on the current `package.path` value in Lua when `moonscript` is +required. Any search paths in `package.path` ending in `.lua` are copied, +rewritten to end in `.moon`, and then inserted in `package.moonpath`. + +The `moonloader` is the function that is responsible for searching +`package.moonpath` for a file available to be included. It is inserted in the +second position of the `package.loaders` table. This means that a matching `.moon` file +will be loaded over a matching `.lua` file that has the same base name. + +For more information on Lua's `package.loaders` see [Lua Reference Manual +— +package.loaders](http://www.lua.org/manual/5.1/manual.html#pdf-package.loaders) + +The `moonloader`, when finding a valid path to a `.moon` file, will parse and +compile the file in memory. The code is then turned into a function using the +built in `load` function, which is run as the module. + +If you are executing MoonScript code with the included `moon` command line tool +then it is not required to include this module before including any other +MoonScript modules. + +## `moonscript.base` Module + +```moononly +moonscript = require "moonscript.base" +``` + +This module contains an assortment of functions for loading and compiling +MoonScript code from within Lua. + +The module provides `load`, `loadfile`, `loadstring` functions, which are +analogous to the similarly named Lua functions. The major difference is that +they load MoonScript code instead of Lua code. + + +```moononly +moonscript = require "moonscript.base" + +fn = moonscript.loadstring 'print "hi!"' +fn! +``` + +All of these functions can take an optional last argument, a table of options. +The only option right now is `implicitly_return_root`. Setting this to `false` +makes it so the file does not implicitly return its last statement. + + +```moononly +moonscript = require "moonscript.base" + +fn = moonscript.loadstring "10" +print fn! -- prints "10" + +fn = moonscript.loadstring "10", implicitly_return_root: false +print fn! -- prints nothing +``` + +One more useful function is provided: `to_lua`. This function takes a string of +MoonScript code and returns the compiled Lua result along with the line mapping +table. If there are any errors then `nil` and the error message are returned. + + +```moononly +import to_lua from require "moonscript.base" + +lua_code, line_tabel = to_lua [[ +x = 124 +print "hello world #{x}" +]] +``` + +Similar to the `load*` functions from above, `to_lua` can take an optional +final argument of a table of options. + +The second return value of `to_lua` is useful if you want to perform line +number reversal. It's a table where the key is a Lua line number and the value +is a character offset from the original MoonScript source. + +## Programmatically Compiling + +If you need finder grained control over the compilation process you can use the +raw parse and compile modules. + +Parsing converts a string of MoonScript into an abstract syntax tree. Compiling +converts an abstract syntax tree into a Lua code string. + +Knowledge of this API may be useful for creating tools to aid the generation of +Lua code from MoonScript code. For example, you could build a macro system by +analyzing and manipulating the abstract syntax tree. Be warned though, the +format of the abstract syntax tree is undocumented and may change in the +future. + +Here is a quick example of how you would compile a MoonScript string to a Lua +String (This is effectively the same as the `to_lua` function described above): + +```moononly +parse = require "moonscript.parse" +compile = require "moonscript.compile" + +moon_code = [[(-> print "hello world")!]] + +tree, err = parse.string moon_code +unless tree + error "Parse error: " .. err + +lua_code, err, pos = compile.tree tree +unless lua_code + error compile.format_error err, pos, moon_code + +-- our code is ready +print lua_code +``` diff --git a/docs/command_line.md b/docs/command_line.md new file mode 100644 index 00000000..a68e3485 --- /dev/null +++ b/docs/command_line.md @@ -0,0 +1,250 @@ +target: reference/command_line +template: reference +title: Command Line Tools +short_name: command_line +-- + +# Command Line Tools + +Two tools are installed with MoonScript, `moon` and `moonc`. + +`moonc` is for compiling MoonScript code to Lua. +`moon` is for running MoonScript code directly. + +## `moon` + +`moon` can be used to run MoonScript files directly from the command line, +without needing a separate compile step. All MoonScript files are compiled in +memory as they are executed. + +```bash +$ moon my_script.moon +``` + +Any MoonScript files that are required will also be compiled on demand as they +are loaded. + +When an error occurs during runtime, the stack trace is rewritten to give line +numbers from the original `.moon` file. + +If you want to disable [error rewriting](#error_rewriting), you can pass the +`-d` flag. A full list of flags can be seen by passing the `-h` or `--help` +flag. + +### Error Rewriting + +Runtime errors are given special attention when running code using the `moon` +command line tool. Because code is written in MoonScript but executed as Lua, +errors that happen during runtime report Lua line numbers. This can make +debugging less than ideal. + +In order to solve this problem MoonScript builds up a table of line number +mappings, allowing the runtime to calculate what line of MoonScript generated +the line of Lua that triggered the error. + +Consider the following file with a bug (note the invalid `z` variable): + +```moon +add_numbers = (x,y) -> x + z -- 1 +print add_numbers 10,0 -- 2 +``` + +The following error is generated: + + moon: scrap.moon:1(3): attempt to perform arithmetic on global 'z' (a nil value) + stack traceback: + scrap.moon:1(3): in function 'add_numbers' + scrap.moon:2(5): in main chunk + + +Notice how next to the file name there are two numbers. The first number is the +rewritten line number. The number in the parentheses is the original Lua line +number. + +The error in this example is being reported on line 1 of the `moon` file, which +corresponds to line 3 of the generated Lua code. The entire stack trace is rewritten in +addition to the error message. + +### Code Coverage + +`moon` lets you run a MoonScript file while keeping track of which lines +are executed with the `-c` flag. + +For example, consider the following `.moon` file: + +```moononly +-- test.moon +first = -> + print "hello" + +second = -> + print "world" + +first! +``` + +We can execute and get a glance of which lines ran: + +```bash +$ moon -c test.moon +``` + +The following output is produced: + + ------| @cool.moon + 1| -- test.moon + * 2| first = -> + * 3| print "hello" + 4| + * 5| second = -> + 6| print "world" + 7| + * 8| first! + 9| + +The star next to the line means that it was executed. Blank lines are not +considered when running so by default they don't get marked as executed. + +## `moonc` + +`moonc` is used for transforming MoonScript files into Lua files. +It takes a list of files, compiles them all, and creates the associated `.lua` +files in the same directories. + +```bash +$ moonc my_script1.moon my_script2.moon ... +``` + +You can control where the compiled files are put using the `-t` flag, followed +by a directory. + +`moonc` can also take a directory as an argument, and it will recursively scan +for all MoonScript files and compile them. + +`moonc` can write to standard out by passing the `-p` flag. + +The `-w` flag can be used to enable watch mode. `moonc` will stay running, and +watch for changes to the input files. If any of them change then they will be +compiled automatically. + +A full list of flags can be seen by passing the `-h` or `--help` flag. + +### Linter + +`moonc` contains a [lint][1] tool +for statically detecting potential problems with code. The current linter only +has one test: it detects the use of global variables. + +You can execute the linter with the `-l` flag. When the linting flag is +provided only linting takes place and no compiled code is generated. + +```bash +moonc -l file1.moon file2.moon +``` + +Like when compiling, you can also pass a directory as a command line argument +to recursively process all the `.moon` files. + +#### Global Variable Checking + +It's considered good practice to avoid using global variables and create local +variables for all the values referenced. A good case for not using global +variables is that you can analyize the code ahead of time without the need to +execute it to find references to undeclared variables. + +MoonScript makes it difficult to declare global variables by forcing you to be +explicit with the `export` keyword, so it's a good candidate for doing this +kind of linting. + +Consider the following program with a typo: (`my_number` is spelled wrong as +`my_nmuber` in the function) + +```moononly +-- lint_example.moon +my_number = 1234 + +some_function = -> + -- a contrived example with a small chance to pass + if math.random() < 0.01 + my_nmuber + 10 + +some_function! +``` + +Although there is a bug in this code, it rarely happens during execution. It's +more likely to be missed during development and cause problems in the future. + +Running the linter immediately identifies the problem: + +```bash +$ moonc -l lint_example.moon +``` + +Outputs: + + ./lint_example.moon + + line 7: accessing global my_nmuber + ================================== + > my_nmuber + 10 + +#### Global Variable Whitelist + +In most circumstances it's impossible to avoid using some global variables. For +example, to access any of the built in modules or functions you typically +access them globally. + +For this reason a global variable whitelist is used. It's a list of global +variables that are allowed to be used. A default whitelist is provided that +contains all of Lua's built in functions and modules. + +You can create your own entires in the whitelist as well. For example, the +testing framework [Busted](http://olivinelabs.com/busted) uses a collection of +global functions (like `describe`, `before_each`, `setup`) to make writing +tests easy. + +It would be nice if we could allow all of those global functions to be called +for `.moon` files located in the `spec/` directory. We can do that by creating +a `lint_config` file. + +`lint_config` is a regular MoonScript or Lua file that provides configuration +for the linter. One of those settings is `whitelist_globals`. + +To create a configuration for Busted we might do something like this: + +```moononly +-- lint_config.moon +{ + whitelist_globals: { + ["spec/"]: { + "it", "describe", "setup", "teardown", + "before_each", "after_each", "pending" + } + } +} +``` + +Compile the file: + +```bash +$ moonc lint_config.moon +``` + +Then run the linter on your entire project: + +```bash +$ moonc -l . +``` + +The whitelisted global references in `spec/` will no longer raise notices. + +The `whitelist_globals` property of the `lint_config` is a table where the keys +are Lua patterns that match file names, and the values are an array of globals +that are allowed. + +Multiple patterns in `whitelist_globals` can match a single file, the union of +the allowed globals will be used when linting that file. + + + [1]: http://en.wikipedia.org/wiki/Lint_(software) + diff --git a/docs/reference.md b/docs/reference.md index 8bcfacf4..a67fd332 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -1,8 +1,9 @@ - target: reference/index - template: reference - title: MoonScript v0.2.5 - Language Guide - short_name: lang +target: reference/index +template: reference +title: Language Guide +short_name: lang -- + MoonScript is a programming language that compiles to [Lua](http://www.lua.org). This guide expects the reader to have basic familiarity with Lua. For each code snippet below, the MoonScript is on the @@ -24,8 +25,8 @@ MoonScript is a whitespace sensitive language. This means that instead of using `do` and `end` (or `{` and `}`) to delimit sections of code we use line-breaks and indentation. -This means that how you indent you code is important. Luckily MoonScript -doesn't care how you do it but it's important to be consistent. +This means that how you indent your code is important. Luckily MoonScript +doesn't care how you do it but only requires that you be consistent. An indent must be at least 1 space or 1 tab, but you can use as many as you like. All the code snippets on this page will use two spaces. @@ -1555,335 +1556,6 @@ my_second_function = -> print "another function" If you need to forward declare your values so you can access them regardless of their written order you can add `local *` to the top of your file. -# MoonScript API - -## `moonscript` Module - -Upon installing MoonScript, a `moonscript` module is made available. The best -use of this module is making your Lua's require function MoonScript aware. - -```lua -require "moonscript" -``` - -After `moonscript` is required, Lua's package loader is updated to search for -`.moon` files on any subsequent calls to `require`. The search path for `.moon` -files is based on the current `package.path` value in Lua when `moonscript` is -required. Any search paths in `package.path` ending in `.lua` are copied, -rewritten to end in `.moon`, and then inserted in `package.moonpath`. - -The `moonloader` is the function that is responsible for searching -`package.moonpath` for a file available to be included. It is inserted in the -second position of the `package.loaders` table. This means that a matching `.moon` file -will be loaded over a matching `.lua` file that has the same base name. - -For more information on Lua's `package.loaders` see [Lua Reference Manual -— -package.loaders](http://www.lua.org/manual/5.1/manual.html#pdf-package.loaders) - -The `moonloader`, when finding a valid path to a `.moon` file, will parse and -compile the file in memory. The code is then turned into a function using the -built in `load` function, which is run as the module. - -### Load Functions - -MoonScript provides `moonscript.load`, `moonscript.loadfile`, -`mooonscript.loadstring`, which are analogous to Lua's `load`, `loadfile`, and -`loadstring`. - -The MoonScript functions work the same as their counterparts, except they deal -with MoonScript code instead of Lua Code. - - -```moononly -moonscript = require "moonscript" - -fn = moonscript.loadstring 'print "hi!"' -fn! -``` - -All of these functions can take an optional last argument, a table of options. -The only option right now is `implicitly_return_root`. Setting this to `false` -makes it so the file does not implicitly return its last statement. - - -```moononly -moonscript = require "moonscript" - -fn = moonscript.loadstring "10" -print fn! -- prints "10" - -fn = moonscript.loadstring "10", implicitly_return_root: false -print fn! -- prints nothing -``` - -## Error Rewriting - -Runtime errors are given special attention when running code using the `moon` -binary. Because we start off as MoonScript, but run code as Lua, errors that -happen during runtime report their line numbers as they are in the compiled -file. This can make debugging particularly difficult. - -Consider the following file with a bug (note the invalid `z` variable): - -```moon -add_numbers = (x,y) -> x + z -- 1 -print add_numbers 10,0 -- 2 -``` - -The following error is generated: - - moon: scrap.moon:1(3): attempt to perform arithmetic on global 'z' (a nil value) - stack traceback: - scrap.moon:1(3): in function 'add_numbers' - scrap.moon:2(5): in main chunk - - -Notice how next to the file name there are two numbers. The first number is the -rewritten line number. The number in the parentheses is the original Lua line -number. - -The error in this example is being reported on line 1 of the `moon` file, which -corresponds to line 3 of the generated Lua code. The entire stack trace is rewritten in -addition to the error message. - -## Programmatically Compiling - -The MoonScript module also contains methods for parsing MoonScript text into an -abstract syntax tree, and compiling an instance of a tree into Lua source code. - -Knowledge of this API may be useful for creating tools to aid the generation of -Lua code from MoonScript code. - -Here is a quick example of how you would compile a MoonScript string to a Lua -String: - -```moononly -parse = require "moonscript.parse" -compile = require "moonscript.compile" - -moon_code = [[(-> print "hello world")!]] - -tree, err = parse.string moon_code -if not tree - error "Parse error: " .. err - -lua_code, err, pos = compile.tree tree -if not lua_code - error compile.format_error err, pos, moon_code - --- our code is ready -print lua_code -``` - -# Command Line Use - -Two tools are installed with MoonScript, `moon` and `moonc`. - -`moonc` is for compiling MoonScript code to Lua. -`moon` is for running MoonsScript code directly. - -## `moon` - -`moon` can be used to run MoonsScript files directly from the command line, -without needing a separate compile step. All MoonsScript files are compiled in -memory as they are run. - -```bash -$ moon my_script.moon -``` - -Any MoonScript files that are required will also be compiled and run -automatically. - -When an error occurs during runtime, the stack trace is rewritten to give line -numbers from the original `.moon` file. - -If you want to disable [error rewriting](#error_rewriting), you can pass the -`-d` flag. A full list of flags can be seen by passing the `-h` or `--help` -flag. - -### Code Coverage - -`moon` lets you run a MoonScript file while keeping track of which lines -are executed with the `-c` flag. - -For example, consider the following `.moon` file: - -```moononly --- test.moon -first = -> - print "hello" - -second = -> - print "world" - -first! -``` - -We can execute and get a glance of which lines ran: - -```bash -$ moon -c test.moon -``` - -The following output is produced: - - ------| @cool.moon - 1| -- test.moon - * 2| first = -> - * 3| print "hello" - 4| - * 5| second = -> - 6| print "world" - 7| - * 8| first! - 9| - -The star next to the line means that it was executed. Blank lines are not -considered when running so by default they don't get marked as executed. - -## `moonc` - -`moonc` is used for transforming MoonsScript files into Lua files. -It takes a list of files, compiles them all, and creates the associated `.lua` -files in the same directories. - -```bash -$ moonc my_script1.moon my_script2.moon ... -``` - -You can control where the compiled files are put using the `-t` flag, followed -by a directory. - -`moonc` can also take a directory as an argument, and it will recursively scan -for all MoonScript files and compile them. - -`moonc` can write to standard out by passing the `-p` flag. - -The `-w` flag can be used to enable watch mode. `moonc` will stay running, and -watch for changes to the input files. If any of them change then they will be -compiled automatically. - -A full list of flags can be seen by passing the `-h` or `--help` flag. - -### Linter - -`moonc` contains a [lint][1] tool -for statically detecting potential problems with code. The current linter only -has one test: it detects the use of global variables. - -You can execute the linter with the `-l` flag. When the linting flag is -provided only linting takes place and no compiled code is generated. - -```bash -moonc -l file1.moon file2.moon -``` - -Like when compiling, you can also pass a directory as a command line argument -to recursively process all the `.moon` files. - -#### Global Variable Checking - -It's considered good practice to avoid using global variables and create local -variables for all the values referenced. A good case for not using global -variables is that you can analyize the code ahead of time without the need to -execute it to find references to undeclared variables. - -MoonScript makes it difficult to declare global variables by forcing you to be -explicit with the `export` keyword, so it's a good candidate for doing this -kind of linting. - -Consider the following program with a typo: (`my_number` is spelled wrong as -`my_nmuber` in the function) - -```moononly --- lint_example.moon -my_number = 1234 - -some_function = -> - -- a contrived example with a small chance to pass - if math.random() < 0.01 - my_nmuber + 10 - -some_function! -``` - -Although there is a bug in this code, it rarely happens during execution. It's -more likely to be missed during development and cause problems in the future. - -Running the linter immediately identifies the problem: - -```bash -$ moonc -l lint_example.moon -``` - -Outputs: - - ./lint_example.moon - - line 7: accessing global my_nmuber - ================================== - > my_nmuber + 10 - - -##### Global Variable Whitelist - -In most circumstances it's impossible to avoid using some global variables. For -example, to access any of the built in modules or functions you typically -access them globally. - -For this reason a global variable whitelist is used. It's a list of global -variables that are allowed to be used. A default whitelist is provided that -contains all of Lua's built in functions and modules. - -You can create your own entires in the whitelist as well. For example, the -testing framework [Busted](http://olivinelabs.com/busted) uses a collection of -global functions (like `describe`, `before_each`, `setup`) to make writing -tests easy. - -It would be nice if we could allow all of those global functions to be called -for `.moon` files located in the `spec/` directory. We can do that by creating -a `lint_config` file. - -`lint_config` is a regular MoonScript or Lua file that provides configuration -for the linter. One of those settings is `whitelist_globals`. - -To create a configuration for Busted we might do something like this: - -```moononly --- lint_config.moon -{ - whitelist_globals: { - ["spec/"]: { - "it", "describe", "setup", "teardown", - "before_each", "after_each", "pending" - } - } -} -``` - -Compile the file: - -```bash -$ moonc lint_config.moon -``` - -Then run the linter on your entire project: - -```bash -$ moonc -l . -``` - -The whitelisted global references in `spec/` will no longer raise notices. - -The `whitelist_globals` property of the `lint_config` is a table where the keys -are Lua patterns that match file names, and the values are an array of globals -that are allowed. - -Multiple patterns in `whitelist_globals` can match a single file, the union of -the allowed globals will be used when linting that file. - # License (MIT) Copyright (C) 2014 by Leaf Corcoran @@ -1907,4 +1579,3 @@ the allowed globals will be used when linting that file. THE SOFTWARE. - [1]: http://en.wikipedia.org/wiki/Lint_(software) diff --git a/docs/standard_lib.md b/docs/standard_lib.md index d76fe8fb..f2686081 100644 --- a/docs/standard_lib.md +++ b/docs/standard_lib.md @@ -1,7 +1,7 @@ - target: reference/standard_lib - template: reference - title: MoonScript v0.2.5 - Standard Library - short_name: stdlib +target: reference/standard_lib +template: reference +title: Standard Library +short_name: stdlib -- The MoonScript installation comes with a small kernel of functions that can be From b7f5e79bd329c7d95b6970b66c06f161dafeb5ce Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 18 Jun 2014 23:55:49 -0700 Subject: [PATCH 222/554] update version number, update changelog --- CHANGELOG.md | 9 +++++++++ moonscript/version.moon | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4464d817..00c559fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,13 @@ +# MoonScript v0.2.6 (2014-6-18) + +## Bugs Fixes + +* Fixes to posmap generation for multi-line mappings and variable declarations +* Prefix file name with `@` when loading code so stack traces tread it as file +* Fix bug where `moonc` couldn't work with absolute paths +* Improve target file path generation for `moonc` + # MoonScript v0.2.5 (2014-3-5) ## New Things diff --git a/moonscript/version.moon b/moonscript/version.moon index 62886737..156e240b 100644 --- a/moonscript/version.moon +++ b/moonscript/version.moon @@ -1,5 +1,5 @@ -version = "0.2.5" +version = "0.2.6" { version: version, From 13da7286f8a78360a8a2e1b882212ef44a24c99b Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 19 Jun 2014 00:00:10 -0700 Subject: [PATCH 223/554] restore -t to watch mode --- bin/moonc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bin/moonc b/bin/moonc index d68302a9..c408cc81 100755 --- a/bin/moonc +++ b/bin/moonc @@ -58,7 +58,6 @@ local mkdir = moonc.mkdir local normalize_dir = moonc.normalize_dir local parse_dir = moonc.parse_dir local parse_file = moonc.parse_file -local convert_path = moonc.convert_path local compile_and_write = moonc.compile_and_write local path_to_target = moonc.path_to_target @@ -271,7 +270,7 @@ if opts.w then end for fname in protected do - local target = convert_path(fname) + local target = path_to_target(fname, opts.t) local success, err = compile_and_write(fname, target) if not success then io.stderr:write(table.concat({ From fe2984f85d49cee8139813a5307460fb2e7493c4 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 19 Jun 2014 00:04:10 -0700 Subject: [PATCH 224/554] restore -o --- bin/moonc | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/bin/moonc b/bin/moonc index c408cc81..3466d330 100755 --- a/bin/moonc +++ b/bin/moonc @@ -118,7 +118,9 @@ local function get_files(fname, files) return files end -if opts.h then print_help() end +if opts.h then + print_help() +end if read_stdin then local parse = require "moonscript.parse" @@ -156,6 +158,10 @@ files = remove_dups(files, function(f) return f[2] end) +if opts.o and #files > 1 then + print_help("-o can not be used with multiple input files") +end + local function get_sleep_func() local sleep if not pcall(function() @@ -271,6 +277,11 @@ if opts.w then for fname in protected do local target = path_to_target(fname, opts.t) + + if opts.o then + target = opts.o + end + local success, err = compile_and_write(fname, target) if not success then io.stderr:write(table.concat({ @@ -299,6 +310,10 @@ elseif opts.l then else for _, tuple in ipairs(files) do local fname, target = unpack(tuple) + if opts.o then + target = opts.o + end + local success, err = compile_and_write(fname, target) if not success then io.stderr:write(fname .. "\t" .. err .. "\n") From 210fd7cf071f39d1a8ed29e91f64cdf057a8e5da Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 19 Jun 2014 00:24:52 -0700 Subject: [PATCH 225/554] rebuild version --- moonscript/version.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/moonscript/version.lua b/moonscript/version.lua index 8dda91c7..ff223d3a 100644 --- a/moonscript/version.lua +++ b/moonscript/version.lua @@ -1,4 +1,4 @@ -local version = "0.2.5" +local version = "0.2.6" return { version = version, print_version = function() From de0717027d8ef3b06c0dd7677b694205b36dce13 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 19 Jun 2014 00:41:59 -0700 Subject: [PATCH 226/554] fix typo --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 00c559fb..91e400eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ # MoonScript v0.2.6 (2014-6-18) -## Bugs Fixes +## Bug Fixes * Fixes to posmap generation for multi-line mappings and variable declarations * Prefix file name with `@` when loading code so stack traces tread it as file @@ -16,7 +16,7 @@ * New [linting tool](http://moonscript.org/reference/#linter) built into `moonc`, identifies global variable references that don't pass whitelist * Numbers can have `LL` and `ULL` suffixes for LuaJIT -## Bugs Fixes +## Bug Fixes * Error messages from `moonc` are written to standard error * Moonloader correctly throws error when moon file can't be parsed, instead of skipping the module From 6d5dbf7237fa0d7f5f9ccba64714ca0cf26724df Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 8 Jul 2014 23:28:45 -0700 Subject: [PATCH 227/554] fix broken moonc -p --- bin/moonc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bin/moonc b/bin/moonc index 3466d330..3b276aad 100755 --- a/bin/moonc +++ b/bin/moonc @@ -314,7 +314,9 @@ else target = opts.o end - local success, err = compile_and_write(fname, target) + local success, err = compile_and_write(fname, target, { + print = opts.p + }) if not success then io.stderr:write(fname .. "\t" .. err .. "\n") os.exit(1) From 5c44d987752e779bc6be5b8eebef68e365722f60 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 17 Jun 2014 17:40:24 -0700 Subject: [PATCH 228/554] assert --- moonscript/errors.lua | 2 +- moonscript/errors.moon | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/moonscript/errors.lua b/moonscript/errors.lua index bdf5811c..d85c3162 100644 --- a/moonscript/errors.lua +++ b/moonscript/errors.lua @@ -18,7 +18,7 @@ local lookup_line lookup_line = function(fname, pos, cache) if not cache[fname] then do - local _with_0 = io.open(fname) + local _with_0 = assert(io.open(fname)) cache[fname] = _with_0:read("*a") _with_0:close() end diff --git a/moonscript/errors.moon b/moonscript/errors.moon index a6543adb..b04c5671 100644 --- a/moonscript/errors.moon +++ b/moonscript/errors.moon @@ -12,7 +12,7 @@ user_error = (...) -> -- find the line number of `pos` chars into fname lookup_line = (fname, pos, cache) -> if not cache[fname] - with io.open fname + with assert io.open(fname) cache[fname] = \read "*a" \close! pos_to_line cache[fname], pos From e191ba9858c9ea933dac5c133fafa1b8c7c66f15 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 18 Jul 2014 18:08:19 -0700 Subject: [PATCH 229/554] fix printing wrong thing --- moonscript/cmd/moonc.lua | 2 +- moonscript/cmd/moonc.moon | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/moonscript/cmd/moonc.lua b/moonscript/cmd/moonc.lua index 55009c9b..dc53cd52 100644 --- a/moonscript/cmd/moonc.lua +++ b/moonscript/cmd/moonc.lua @@ -141,7 +141,7 @@ compile_and_write = function(src, dest, opts) return true end if opts.print then - print(text) + print(code) return true end return write_file(dest, code) diff --git a/moonscript/cmd/moonc.moon b/moonscript/cmd/moonc.moon index 8cb2bbb2..6b8b206b 100644 --- a/moonscript/cmd/moonc.moon +++ b/moonscript/cmd/moonc.moon @@ -137,7 +137,7 @@ compile_and_write = (src, dest, opts={}) -> return true if opts.print - print text + print code return true write_file dest, code From 3180dd234bd94e856f312668cec6a818cc2f393f Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 18 Jul 2014 18:10:27 -0700 Subject: [PATCH 230/554] add logo and build status badge --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index abfd3d39..31d2f52d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ # MoonScript +[![MoonScript](http://leafo.net/dump/sailormoonscript.png)](http://moonscript.org) + +[![Build Status](https://travis-ci.org/leafo/moonscript.svg?branch=master)](https://travis-ci.org/leafo/moonscript) + MoonScript is a programmer friendly language that compiles into [Lua](http://www.lua.org/). It gives you the power of the fastest scripting language combined with a rich set of features. It runs on Lua 5.1 and 5.2. From 3d4bdf818d26ee5862b57cbfd92e671566ca6089 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 29 Jul 2014 22:54:11 -0700 Subject: [PATCH 231/554] use older version of busted for travis --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 74670737..2cb435d0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ language: c install: - sudo apt-get install luarocks - - sudo luarocks install busted + - sudo luarocks install https://rocks.moonscript.org/manifests/olivine-labs/busted-1.11.1-1.rockspec - sudo luarocks make script: busted From 64232fef0367cf1888a5d67db8ba09a152b1455a Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 29 Jul 2014 23:04:52 -0700 Subject: [PATCH 232/554] update travis to install busted from moonrocks --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2cb435d0..114ffca2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ language: c install: - sudo apt-get install luarocks - - sudo luarocks install https://rocks.moonscript.org/manifests/olivine-labs/busted-1.11.1-1.rockspec + - sudo luarocks install --server=http://rocks.moonscript.org https://rocks.moonscript.org/manifests/olivine-labs/busted-1.11.1-1.rockspec - sudo luarocks make script: busted From b7de66f45a9fd3227f1f37f615754dac86e835c1 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 29 Jul 2014 23:14:54 -0700 Subject: [PATCH 233/554] travis fix pt. 2 --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 114ffca2..346cc94e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,9 @@ language: c install: - sudo apt-get install luarocks - - sudo luarocks install --server=http://rocks.moonscript.org https://rocks.moonscript.org/manifests/olivine-labs/busted-1.11.1-1.rockspec + - mkdir -p ~/.luarocks + - echo 'rocks_servers = { "http://rocks.moonscript.org" }' > ~/.luarocks/config.lua + - sudo luarocks install https://rocks.moonscript.org/manifests/olivine-labs/busted-1.11.1-1.rockspec - sudo luarocks make script: busted From a6e66737ddf5478f4010f857dfe922106e346cf5 Mon Sep 17 00:00:00 2001 From: Jason Tu Date: Sun, 17 Aug 2014 22:29:30 -0400 Subject: [PATCH 234/554] Fix for moonc -w --- bin/moonc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/moonc b/bin/moonc index 3b276aad..4dfd2358 100755 --- a/bin/moonc +++ b/bin/moonc @@ -165,7 +165,7 @@ end local function get_sleep_func() local sleep if not pcall(function() - require "socket" + local socket = require "socket" sleep = socket.sleep end) then -- This is set by moonc.c in windows binaries From da6c76b7e436cb2b2f4e44db2022665262bc5d02 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 2 Sep 2014 20:31:08 -0700 Subject: [PATCH 235/554] simplify single name destructures/imports --- moonscript/transform/destructure.lua | 10 +++++++-- moonscript/transform/destructure.moon | 8 +++++-- spec/outputs/class.lua | 5 +---- spec/outputs/destructure.lua | 30 ++++++--------------------- spec/outputs/import.lua | 10 ++------- 5 files changed, 23 insertions(+), 40 deletions(-) diff --git a/moonscript/transform/destructure.lua b/moonscript/transform/destructure.lua index f7a5166c..38e9bc55 100644 --- a/moonscript/transform/destructure.lua +++ b/moonscript/transform/destructure.lua @@ -124,7 +124,7 @@ build_assign = function(scope, destruct_literal, receiver) values } local obj - if scope:is_local(receiver) then + if scope:is_local(receiver) or #extracted_names == 1 then obj = receiver else do @@ -143,7 +143,13 @@ build_assign = function(scope, destruct_literal, receiver) for _index_0 = 1, #extracted_names do local tuple = extracted_names[_index_0] insert(names, tuple[1]) - insert(values, NameProxy.chain(obj, unpack(tuple[2]))) + local chain + if obj then + chain = NameProxy.chain(obj, unpack(tuple[2])) + else + chain = "nil" + end + insert(values, chain) end return build.group({ { diff --git a/moonscript/transform/destructure.moon b/moonscript/transform/destructure.moon index 1547ccfc..ca80bc25 100644 --- a/moonscript/transform/destructure.moon +++ b/moonscript/transform/destructure.moon @@ -59,7 +59,7 @@ build_assign = (scope, destruct_literal, receiver) -> inner = {"assign", names, values} - obj = if scope\is_local receiver + obj = if scope\is_local(receiver) or #extracted_names == 1 receiver else with obj = NameProxy "obj" @@ -70,7 +70,11 @@ build_assign = (scope, destruct_literal, receiver) -> for tuple in *extracted_names insert names, tuple[1] - insert values, NameProxy.chain obj, unpack tuple[2] + chain = if obj + NameProxy.chain obj, unpack tuple[2] + else + "nil" + insert values, chain build.group { {"declare", names} diff --git a/spec/outputs/class.lua b/spec/outputs/class.lua index 67227911..35c7153d 100644 --- a/spec/outputs/class.lua +++ b/spec/outputs/class.lua @@ -687,10 +687,7 @@ do _base_0.__class = _class_0 local self = _class_0 val = 23 - do - local _obj_0 = table - insert = _obj_0.insert - end + insert = table.insert Something = _class_0 end do diff --git a/spec/outputs/destructure.lua b/spec/outputs/destructure.lua index 28315438..8254e3c9 100644 --- a/spec/outputs/destructure.lua +++ b/spec/outputs/destructure.lua @@ -26,27 +26,15 @@ do local _obj_0 = yeah a, b, c, d = _obj_0.a, _obj_0.b, _obj_0.c, _obj_0.d end - do - local _obj_0 = one - a = _obj_0[1] - end + a = one[1] local _ = two - do - local _obj_0 = one - b = _obj_0[1] - end + b = one[1] c = nil - do - local _obj_0 = one - d = _obj_0[1] - end + d = one[1] local e = two local x = one local y - do - local _obj_0 = two - y = _obj_0[1] - end + y = two[1] local xx, yy = 1, 2 do local _obj_0 = { @@ -77,18 +65,12 @@ do name, street, city = futurists.poet.name, futurists.poet.address[1], futurists.poet.address[2] end do - do - local _obj_0 = x - self.world = _obj_0[1] - end + self.world = x[1] do local _obj_0 = x a.b, c.y, func().z = _obj_0[1], _obj_0[2], _obj_0[3] end - do - local _obj_0 = x - self.world = _obj_0.world - end + self.world = x.world end do local thing = { diff --git a/spec/outputs/import.lua b/spec/outputs/import.lua index f7467f4f..4c6520eb 100644 --- a/spec/outputs/import.lua +++ b/spec/outputs/import.lua @@ -1,8 +1,5 @@ local hello -do - local _obj_0 = yeah - hello = _obj_0.hello -end +hello = yeah.hello local world do local _obj_0 = table["cool"] @@ -34,10 +31,7 @@ local yumm a, yumm = 3434, "hello" local _table_0 = 232 local something -do - local _obj_0 = a(table) - something = _obj_0.something -end +something = a(table).something if indent then local okay, well do From 163748b8c91f2df226aa8cb81f91c20e1fa1fc62 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 2 Sep 2014 20:32:52 -0700 Subject: [PATCH 236/554] rebuild --- Makefile | 2 +- moonscript/cmd/lint.lua | 15 +++------------ moonscript/cmd/moonc.lua | 10 ++-------- moonscript/compile.lua | 5 +---- moonscript/compile/statement.lua | 5 +---- moonscript/compile/value.lua | 10 ++-------- moonscript/transform.lua | 5 +---- moonscript/transform/destructure.lua | 20 ++++---------------- moonscript/transform/names.lua | 10 ++-------- moonscript/types.lua | 10 ++-------- moonscript/util.lua | 5 +---- 11 files changed, 20 insertions(+), 77 deletions(-) diff --git a/Makefile b/Makefile index 45b90f8a..88085f78 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ global: sudo luarocks make moonscript-dev-1.rockspec compile:: - bin/moonc moon/ moonscript/ + lua5.1 bin/moonc moon/ moonscript/ compile_global: diff --git a/moonscript/cmd/lint.lua b/moonscript/cmd/lint.lua index a8c08903..6dfa4c82 100644 --- a/moonscript/cmd/lint.lua +++ b/moonscript/cmd/lint.lua @@ -1,18 +1,9 @@ local insert -do - local _obj_0 = table - insert = _obj_0.insert -end +insert = table.insert local Set -do - local _obj_0 = require("moonscript.data") - Set = _obj_0.Set -end +Set = require("moonscript.data").Set local Block -do - local _obj_0 = require("moonscript.compile") - Block = _obj_0.Block -end +Block = require("moonscript.compile").Block local default_whitelist = Set({ '_G', '_VERSION', diff --git a/moonscript/cmd/moonc.lua b/moonscript/cmd/moonc.lua index dc53cd52..b64c9f1c 100644 --- a/moonscript/cmd/moonc.lua +++ b/moonscript/cmd/moonc.lua @@ -1,9 +1,6 @@ local lfs = require("lfs") local split -do - local _obj_0 = require("moonscript.util") - split = _obj_0.split -end +split = require("moonscript.util").split local dirsep, dirsep_chars, mkdir, normalize_dir, parse_dir, parse_file, convert_path, format_time, gettime, compile_file_text, write_file, compile_and_write, is_abs_path, path_to_target dirsep = package.config:sub(1, 1) if dirsep == "\\" then @@ -93,10 +90,7 @@ compile_file_text = function(text, fname, opts) end if opts.show_posmap then local debug_posmap - do - local _obj_0 = require("moonscript.util") - debug_posmap = _obj_0.debug_posmap - end + debug_posmap = require("moonscript.util").debug_posmap print("Pos", "Lua", ">>", "Moon") print(debug_posmap(posmap_or_err, text, code)) return true diff --git a/moonscript/compile.lua b/moonscript/compile.lua index aaa42c29..52f39815 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -7,10 +7,7 @@ do NameProxy, LocalName = _obj_0.NameProxy, _obj_0.LocalName end local Set -do - local _obj_0 = require("moonscript.data") - Set = _obj_0.Set -end +Set = require("moonscript.data").Set local ntype, has_value do local _obj_0 = require("moonscript.types") diff --git a/moonscript/compile/statement.lua b/moonscript/compile/statement.lua index 2d2a80c8..2026a88f 100644 --- a/moonscript/compile/statement.lua +++ b/moonscript/compile/statement.lua @@ -2,10 +2,7 @@ local util = require("moonscript.util") local reversed, unpack reversed, unpack = util.reversed, util.unpack local ntype -do - local _obj_0 = require("moonscript.types") - ntype = _obj_0.ntype -end +ntype = require("moonscript.types").ntype local concat, insert do local _obj_0 = table diff --git a/moonscript/compile/value.lua b/moonscript/compile/value.lua index 560352ba..8f8e8f23 100644 --- a/moonscript/compile/value.lua +++ b/moonscript/compile/value.lua @@ -1,15 +1,9 @@ local util = require("moonscript.util") local data = require("moonscript.data") local ntype -do - local _obj_0 = require("moonscript.types") - ntype = _obj_0.ntype -end +ntype = require("moonscript.types").ntype local user_error -do - local _obj_0 = require("moonscript.errors") - user_error = _obj_0.user_error -end +user_error = require("moonscript.errors").user_error local concat, insert do local _obj_0 = table diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 803d5d70..c2499296 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -6,10 +6,7 @@ reversed, unpack = util.reversed, util.unpack local ntype, mtype, build, smart_node, is_slice, value_is_singular ntype, mtype, build, smart_node, is_slice, value_is_singular = types.ntype, types.mtype, types.build, types.smart_node, types.is_slice, types.value_is_singular local insert -do - local _obj_0 = table - insert = _obj_0.insert -end +insert = table.insert local NameProxy, LocalName do local _obj_0 = require("moonscript.transform.names") diff --git a/moonscript/transform/destructure.lua b/moonscript/transform/destructure.lua index 38e9bc55..c0542953 100644 --- a/moonscript/transform/destructure.lua +++ b/moonscript/transform/destructure.lua @@ -4,25 +4,13 @@ do ntype, mtype, build = _obj_0.ntype, _obj_0.mtype, _obj_0.build end local NameProxy -do - local _obj_0 = require("moonscript.transform.names") - NameProxy = _obj_0.NameProxy -end +NameProxy = require("moonscript.transform.names").NameProxy local insert -do - local _obj_0 = table - insert = _obj_0.insert -end +insert = table.insert local unpack -do - local _obj_0 = require("moonscript.util") - unpack = _obj_0.unpack -end +unpack = require("moonscript.util").unpack local user_error -do - local _obj_0 = require("moonscript.errors") - user_error = _obj_0.user_error -end +user_error = require("moonscript.errors").user_error local join join = function(...) do diff --git a/moonscript/transform/names.lua b/moonscript/transform/names.lua index a7584da1..c74a3773 100644 --- a/moonscript/transform/names.lua +++ b/moonscript/transform/names.lua @@ -1,13 +1,7 @@ local build -do - local _obj_0 = require("moonscript.types") - build = _obj_0.build -end +build = require("moonscript.types").build local unpack -do - local _obj_0 = require("moonscript.util") - unpack = _obj_0.unpack -end +unpack = require("moonscript.util").unpack local LocalName do local _base_0 = { diff --git a/moonscript/types.lua b/moonscript/types.lua index aae50c91..ccf1d53a 100644 --- a/moonscript/types.lua +++ b/moonscript/types.lua @@ -1,14 +1,8 @@ local util = require("moonscript.util") local Set -do - local _obj_0 = require("moonscript.data") - Set = _obj_0.Set -end +Set = require("moonscript.data").Set local insert -do - local _obj_0 = table - insert = _obj_0.insert -end +insert = table.insert local unpack unpack = util.unpack local manual_return = Set({ diff --git a/moonscript/util.lua b/moonscript/util.lua index dfb43557..7eddae37 100644 --- a/moonscript/util.lua +++ b/moonscript/util.lua @@ -1,8 +1,5 @@ local concat -do - local _obj_0 = table - concat = _obj_0.concat -end +concat = table.concat local unpack = unpack or table.unpack local type = type local moon = { From bf8de1cf5eb7450b8363d173da9c986e66b43481 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 28 Feb 2015 10:30:43 -0800 Subject: [PATCH 237/554] move extract assign name out, add statement compiles as param --- moonscript/compile.lua | 35 ++++++++++++++++++++--------------- moonscript/compile.moon | 39 +++++++++++++++++++++++---------------- 2 files changed, 43 insertions(+), 31 deletions(-) diff --git a/moonscript/compile.lua b/moonscript/compile.lua index 52f39815..5eab8e6b 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -256,6 +256,7 @@ do export_all = false, export_proper = false, value_compilers = value_compilers, + statement_compilers = statement_compilers, __tostring = function(self) local h if "string" == type(self.header) then @@ -288,6 +289,22 @@ do end end end, + extract_assign_name = function(self, node) + local is_local = false + local real_name + local _exp_0 = mtype(node) + if LocalName == _exp_0 then + is_local = true + real_name = node:get_name(self) + elseif NameProxy == _exp_0 then + real_name = node:get_name(self) + elseif "table" == _exp_0 then + real_name = node[1] == "ref" and node[2] + elseif "string" == _exp_0 then + real_name = node + end + return real_name, is_local + end, declare = function(self, names) local undeclared do @@ -297,19 +314,7 @@ do local _continue_0 = false repeat local name = names[_index_0] - local is_local = false - local real_name - local _exp_0 = mtype(name) - if LocalName == _exp_0 then - is_local = true - real_name = name:get_name(self) - elseif NameProxy == _exp_0 then - real_name = name:get_name(self) - elseif "table" == _exp_0 then - real_name = name[1] == "ref" and name[2] - elseif "string" == _exp_0 then - real_name = name - end + local real_name, is_local = self:extract_assign_name(name) if not (is_local or real_name and not self:has_name(real_name, true)) then _continue_0 = true break @@ -450,7 +455,7 @@ do end end, is_stm = function(self, node) - return statement_compilers[ntype(node)] ~= nil + return self.statement_compilers[ntype(node)] ~= nil end, is_value = function(self, node) local t = ntype(node) @@ -516,7 +521,7 @@ do node = self.transform.statement(node) local result do - local fn = statement_compilers[ntype(node)] + local fn = self.statement_compilers[ntype(node)] if fn then result = fn(self, node, ...) else diff --git a/moonscript/compile.moon b/moonscript/compile.moon index af700e10..d05a3bb7 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -162,6 +162,7 @@ class Block export_proper: false value_compilers: value_compilers + statement_compilers: statement_compilers __tostring: => h = if "string" == type @header @@ -211,22 +212,28 @@ class Block if fn = @_listeners[name] fn self, ... + extract_assign_name: (node) => + is_local = false + real_name = switch mtype node + when LocalName + is_local = true + node\get_name self + when NameProxy + node\get_name self + when "table" + node[1] == "ref" and node[2] + when "string" + -- TOOD: some legacy transfomers might use string for ref + node + + real_name, is_local + declare: (names) => undeclared = for name in *names - is_local = false - real_name = switch mtype name - when LocalName - is_local = true - name\get_name self - when NameProxy then name\get_name self - when "table" - name[1] == "ref" and name[2] - when "string" - -- TODO: don't use string literal as ref - name - + real_name, is_local = @extract_assign_name name continue unless is_local or real_name and not @has_name real_name, true - -- put exported names so they can be assigned to in deeper scope + -- this also puts exported names so they can be assigned a new value in + -- deeper scope @put_name real_name continue if @name_exported real_name real_name @@ -322,7 +329,7 @@ class Block \append ... is_stm: (node) => - statement_compilers[ntype node] != nil + @statement_compilers[ntype node] != nil is_value: (node) => t = ntype node @@ -369,8 +376,8 @@ class Block return if not node -- skip blank statements node = @transform.statement node - result = if fn = statement_compilers[ntype(node)] - fn self, node, ... + result = if fn = @statement_compilers[ntype(node)] + fn @, node, ... else -- coerce value into statement if has_value node From 65f177f5c5a43149a00feb34363e093ba592a765 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 28 Feb 2015 10:41:13 -0800 Subject: [PATCH 238/554] remove pattern matcher because it no longer works with latest busted --- spec/lang_spec.moon | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/spec/lang_spec.moon b/spec/lang_spec.moon index 7fd1a3f8..f6612dd8 100644 --- a/spec/lang_spec.moon +++ b/spec/lang_spec.moon @@ -90,12 +90,7 @@ describe "input tests", -> for name in *inputs input = input_fname name - fn = if pattern and not input\match pattern - pending - else - it - - fn input .. " #input", -> + it input .. " #input", -> file_str = read_all input_fname name parse_time, tree, err = benchmark -> parse.string file_str From f70e4629fe3fe84697925651eac5aac37be83478 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 28 Feb 2015 11:05:21 -0800 Subject: [PATCH 239/554] unused variable linter --- moonscript/cmd/lint.lua | 56 +++++++++++++++++++++++++++++++++++++++- moonscript/cmd/lint.moon | 44 ++++++++++++++++++++++++++++++- 2 files changed, 98 insertions(+), 2 deletions(-) diff --git a/moonscript/cmd/lint.lua b/moonscript/cmd/lint.lua index 6dfa4c82..004c2687 100644 --- a/moonscript/cmd/lint.lua +++ b/moonscript/cmd/lint.lua @@ -4,6 +4,8 @@ local Set Set = require("moonscript.data").Set local Block Block = require("moonscript.compile").Block +local mtype +mtype = require("moonscript.util").moon.type local default_whitelist = Set({ '_G', '_VERSION', @@ -52,11 +54,30 @@ local LinterBlock do local _parent_0 = Block local _base_0 = { + lint_check_unused = function(self) + for name, pos in pairs(self.lint_unused_names) do + insert(self:get_root_block().lint_errors, { + "assigned but unused `" .. tostring(name) .. "`", + pos + }) + end + end, + render = function(self, ...) + self:lint_check_unused() + return _parent_0.render(self, ...) + end, block = function(self, ...) + self.get_root_block = self.get_root_block or function() + return self + end do local _with_0 = _parent_0.block(self, ...) _with_0.block = self.block + _with_0.render = self.render + _with_0.get_root_block = self.get_root_block + _with_0.lint_check_unused = self.lint_check_unused _with_0.value_compilers = self.value_compilers + _with_0.statement_compilers = self.statement_compilers return _with_0 end end @@ -76,15 +97,47 @@ do local name = val[2] if not (block:has_name(name) or whitelist_globals[name] or name:match("%.")) then insert(self.lint_errors, { - "accessing global " .. tostring(name), + "accessing global `" .. tostring(name) .. "`", val[-1] }) end + do + local unused = block.lint_unused_names + if unused then + unused[name] = nil + end + end return vc.ref(block, val) end }, { __index = vc }) + local sc = self.statement_compilers + self.statement_compilers = setmetatable({ + assign = function(block, node) + local _, names, values = unpack(node) + for _index_0 = 1, #names do + local _continue_0 = false + repeat + local name = names[_index_0] + local real_name, is_local = block:extract_assign_name(name) + if not (is_local or real_name and not block:has_name(real_name, true)) then + _continue_0 = true + break + end + block.lint_unused_names = block.lint_unused_names or { } + block.lint_unused_names[real_name] = node[-1] or true + _continue_0 = true + until true + if not _continue_0 then + break + end + end + return sc.assign(block, node) + end + }, { + __index = sc + }) end, __base = _base_0, __name = "LinterBlock", @@ -189,6 +242,7 @@ lint_code = function(code, name, whitelist_globals) end local scope = LinterBlock(whitelist_globals) scope:stms(tree) + scope:lint_check_unused() return format_lint(scope.lint_errors, code, name) end local lint_file diff --git a/moonscript/cmd/lint.moon b/moonscript/cmd/lint.moon index 4add665b..180429cc 100644 --- a/moonscript/cmd/lint.moon +++ b/moonscript/cmd/lint.moon @@ -3,6 +3,8 @@ import insert from table import Set from require "moonscript.data" import Block from require "moonscript.compile" +{type: mtype} = require("moonscript.util").moon + -- globals allowed to be referenced default_whitelist = Set { '_G' @@ -61,17 +63,55 @@ class LinterBlock extends Block name = val[2] unless block\has_name(name) or whitelist_globals[name] or name\match "%." insert @lint_errors, { - "accessing global #{name}" + "accessing global `#{name}`" val[-1] } + if unused = block.lint_unused_names + unused[name] = nil + vc.ref block, val }, __index: vc + sc = @statement_compilers + @statement_compilers = setmetatable { + assign: (block, node) -> + _, names, values = unpack node + -- extract the names to be declared + for name in *names + real_name, is_local = block\extract_assign_name name + -- already defined in some other scope + unless is_local or real_name and not block\has_name real_name, true + continue + + block.lint_unused_names or= {} + block.lint_unused_names[real_name] = node[-1] or true + + sc.assign block, node + }, __index: sc + + + lint_check_unused: => + for name, pos in pairs @lint_unused_names + insert @get_root_block!.lint_errors, { + "assigned but unused `#{name}`" + pos + } + + render: (...) => + @lint_check_unused! + super ... + block: (...) => + @get_root_block or= -> @ + with super ... .block = @block + .render = @render + .get_root_block = @get_root_block + .lint_check_unused = @lint_check_unused .value_compilers = @value_compilers + .statement_compilers = @statement_compilers format_lint = (errors, code, header) -> return unless next errors @@ -127,6 +167,8 @@ lint_code = (code, name="string input", whitelist_globals) -> scope = LinterBlock whitelist_globals scope\stms tree + scope\lint_check_unused! + format_lint scope.lint_errors, code, name lint_file = (fname) -> From 9f7aae7827b4d8ff6dccba87a6e50404f5278d2d Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 28 Feb 2015 11:06:49 -0800 Subject: [PATCH 240/554] clean up makefile --- Makefile | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 88085f78..4781fa3a 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,6 @@ +.PHONY: test local compile watch lint -test:: +test: busted -p "_spec.moon$$" local: compile @@ -8,12 +9,11 @@ local: compile global: sudo luarocks make moonscript-dev-1.rockspec -compile:: +compile: lua5.1 bin/moonc moon/ moonscript/ - -compile_global: - moonc moon/ moonscript/ - watch: moonc moon/ moonscript/ && moonc -w moon/ moonscript/ + +lint: + moonc -l moonscript moon From d19969c2d917d36651993b0a18a763ee4ed5574b Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 28 Feb 2015 11:13:33 -0800 Subject: [PATCH 241/554] don't include autogenerated names and _ in unused linter --- moonscript/cmd/lint.lua | 13 ++++++++++++- moonscript/cmd/lint.moon | 9 ++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/moonscript/cmd/lint.lua b/moonscript/cmd/lint.lua index 004c2687..af37c201 100644 --- a/moonscript/cmd/lint.lua +++ b/moonscript/cmd/lint.lua @@ -55,6 +55,9 @@ do local _parent_0 = Block local _base_0 = { lint_check_unused = function(self) + if not (self.lint_unused_names) then + return + end for name, pos in pairs(self.lint_unused_names) do insert(self:get_root_block().lint_errors, { "assigned but unused `" .. tostring(name) .. "`", @@ -120,13 +123,21 @@ do local _continue_0 = false repeat local name = names[_index_0] + if type(name) == "table" and name[1] == "temp_name" then + _continue_0 = true + break + end local real_name, is_local = block:extract_assign_name(name) if not (is_local or real_name and not block:has_name(real_name, true)) then _continue_0 = true break end + if real_name == "_" then + _continue_0 = true + break + end block.lint_unused_names = block.lint_unused_names or { } - block.lint_unused_names[real_name] = node[-1] or true + block.lint_unused_names[real_name] = node[-1] or 0 _continue_0 = true until true if not _continue_0 then diff --git a/moonscript/cmd/lint.moon b/moonscript/cmd/lint.moon index 180429cc..55f93254 100644 --- a/moonscript/cmd/lint.moon +++ b/moonscript/cmd/lint.moon @@ -79,19 +79,26 @@ class LinterBlock extends Block _, names, values = unpack node -- extract the names to be declared for name in *names + -- don't include autogenerated names + if type(name) == "table" and name[1] == "temp_name" + continue + real_name, is_local = block\extract_assign_name name -- already defined in some other scope unless is_local or real_name and not block\has_name real_name, true continue + continue if real_name == "_" + block.lint_unused_names or= {} - block.lint_unused_names[real_name] = node[-1] or true + block.lint_unused_names[real_name] = node[-1] or 0 sc.assign block, node }, __index: sc lint_check_unused: => + return unless @lint_unused_names for name, pos in pairs @lint_unused_names insert @get_root_block!.lint_errors, { "assigned but unused `#{name}`" From 182969dc81591b29095909e8f0c9bbcf240654c9 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 28 Feb 2015 11:18:21 -0800 Subject: [PATCH 242/554] sort and group unused names --- moonscript/cmd/lint.lua | 38 +++++++++++++++++++++++++++++++++++++- moonscript/cmd/lint.moon | 12 +++++++++++- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/moonscript/cmd/lint.lua b/moonscript/cmd/lint.lua index af37c201..b0f607da 100644 --- a/moonscript/cmd/lint.lua +++ b/moonscript/cmd/lint.lua @@ -58,9 +58,42 @@ do if not (self.lint_unused_names) then return end + local names_by_position = { } for name, pos in pairs(self.lint_unused_names) do + names_by_position[pos] = names_by_position[pos] or { } + insert(names_by_position[pos], name) + end + local tuples + do + local _accum_0 = { } + local _len_0 = 1 + for pos, names in pairs(names_by_position) do + _accum_0[_len_0] = { + pos, + names + } + _len_0 = _len_0 + 1 + end + tuples = _accum_0 + end + table.sort(tuples, function(a, b) + return a[1] < b[1] + end) + for _index_0 = 1, #tuples do + local _des_0 = tuples[_index_0] + local pos, names + pos, names = _des_0[1], _des_0[2] insert(self:get_root_block().lint_errors, { - "assigned but unused `" .. tostring(name) .. "`", + "assigned but unused " .. tostring(table.concat((function() + local _accum_0 = { } + local _len_0 = 1 + for _index_1 = 1, #names do + local n = names[_index_1] + _accum_0[_len_0] = "`" .. tostring(n) .. "`" + _len_0 = _len_0 + 1 + end + return _accum_0 + end)(), ", ")), pos }) end @@ -69,6 +102,9 @@ do self:lint_check_unused() return _parent_0.render(self, ...) end, + get_root_block = function(self) + return self + end, block = function(self, ...) self.get_root_block = self.get_root_block or function() return self diff --git a/moonscript/cmd/lint.moon b/moonscript/cmd/lint.moon index 55f93254..361f15fc 100644 --- a/moonscript/cmd/lint.moon +++ b/moonscript/cmd/lint.moon @@ -99,9 +99,17 @@ class LinterBlock extends Block lint_check_unused: => return unless @lint_unused_names + names_by_position = {} for name, pos in pairs @lint_unused_names + names_by_position[pos] or= {} + insert names_by_position[pos], name + + tuples = [{pos, names} for pos,names in pairs names_by_position] + table.sort tuples, (a,b) -> a[1] < b[1] + + for {pos, names} in *tuples insert @get_root_block!.lint_errors, { - "assigned but unused `#{name}`" + "assigned but unused #{table.concat ["`#{n}`" for n in *names], ", "}" pos } @@ -109,6 +117,8 @@ class LinterBlock extends Block @lint_check_unused! super ... + get_root_block: => @ + block: (...) => @get_root_block or= -> @ From b1ecc7defc6cdac3cf6e75632625944977f02d7e Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 28 Feb 2015 11:22:24 -0800 Subject: [PATCH 243/554] fix get root block for root block --- moonscript/cmd/lint.lua | 11 ++++------- moonscript/cmd/lint.moon | 8 ++++---- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/moonscript/cmd/lint.lua b/moonscript/cmd/lint.lua index b0f607da..d4573f72 100644 --- a/moonscript/cmd/lint.lua +++ b/moonscript/cmd/lint.lua @@ -55,7 +55,7 @@ do local _parent_0 = Block local _base_0 = { lint_check_unused = function(self) - if not (self.lint_unused_names) then + if not (self.lint_unused_names and next(self.lint_unused_names)) then return end local names_by_position = { } @@ -102,13 +102,7 @@ do self:lint_check_unused() return _parent_0.render(self, ...) end, - get_root_block = function(self) - return self - end, block = function(self, ...) - self.get_root_block = self.get_root_block or function() - return self - end do local _with_0 = _parent_0.block(self, ...) _with_0.block = self.block @@ -129,6 +123,9 @@ do whitelist_globals = default_whitelist end _parent_0.__init(self, ...) + self.get_root_block = function() + return self + end self.lint_errors = { } local vc = self.value_compilers self.value_compilers = setmetatable({ diff --git a/moonscript/cmd/lint.moon b/moonscript/cmd/lint.moon index 361f15fc..922e04fa 100644 --- a/moonscript/cmd/lint.moon +++ b/moonscript/cmd/lint.moon @@ -55,6 +55,8 @@ default_whitelist = Set { class LinterBlock extends Block new: (whitelist_globals=default_whitelist, ...) => super ... + @get_root_block = -> @ + @lint_errors = {} vc = @value_compilers @@ -98,7 +100,8 @@ class LinterBlock extends Block lint_check_unused: => - return unless @lint_unused_names + return unless @lint_unused_names and next @lint_unused_names + names_by_position = {} for name, pos in pairs @lint_unused_names names_by_position[pos] or= {} @@ -117,10 +120,7 @@ class LinterBlock extends Block @lint_check_unused! super ... - get_root_block: => @ - block: (...) => - @get_root_block or= -> @ with super ... .block = @block From a79eb19f9e4fcf6a0e9a9efc3e3eab4e521ab443 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 28 Feb 2015 11:26:37 -0800 Subject: [PATCH 244/554] mark used up the block stack --- moonscript/cmd/lint.lua | 32 ++++++++++++++++++++++++-------- moonscript/cmd/lint.moon | 13 ++++++++++--- 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/moonscript/cmd/lint.lua b/moonscript/cmd/lint.lua index d4573f72..1fd80b05 100644 --- a/moonscript/cmd/lint.lua +++ b/moonscript/cmd/lint.lua @@ -54,14 +54,34 @@ local LinterBlock do local _parent_0 = Block local _base_0 = { + lint_mark_used = function(self, name) + if self.lint_unused_names and self.lint_unused_names[name] then + self.lint_unused_names[name] = false + return + end + if self.parent then + return self.parent:lint_mark_used(name) + end + end, lint_check_unused = function(self) if not (self.lint_unused_names and next(self.lint_unused_names)) then return end local names_by_position = { } for name, pos in pairs(self.lint_unused_names) do - names_by_position[pos] = names_by_position[pos] or { } - insert(names_by_position[pos], name) + local _continue_0 = false + repeat + if not (pos) then + _continue_0 = true + break + end + names_by_position[pos] = names_by_position[pos] or { } + insert(names_by_position[pos], name) + _continue_0 = true + until true + if not _continue_0 then + break + end end local tuples do @@ -109,6 +129,7 @@ do _with_0.render = self.render _with_0.get_root_block = self.get_root_block _with_0.lint_check_unused = self.lint_check_unused + _with_0.lint_mark_used = self.lint_mark_used _with_0.value_compilers = self.value_compilers _with_0.statement_compilers = self.statement_compilers return _with_0 @@ -137,12 +158,7 @@ do val[-1] }) end - do - local unused = block.lint_unused_names - if unused then - unused[name] = nil - end - end + block:lint_mark_used(name) return vc.ref(block, val) end }, { diff --git a/moonscript/cmd/lint.moon b/moonscript/cmd/lint.moon index 922e04fa..8317e5c5 100644 --- a/moonscript/cmd/lint.moon +++ b/moonscript/cmd/lint.moon @@ -69,9 +69,7 @@ class LinterBlock extends Block val[-1] } - if unused = block.lint_unused_names - unused[name] = nil - + block\lint_mark_used name vc.ref block, val }, __index: vc @@ -98,12 +96,20 @@ class LinterBlock extends Block sc.assign block, node }, __index: sc + lint_mark_used: (name) => + if @lint_unused_names and @lint_unused_names[name] + @lint_unused_names[name] = false + return + + if @parent + @parent\lint_mark_used name lint_check_unused: => return unless @lint_unused_names and next @lint_unused_names names_by_position = {} for name, pos in pairs @lint_unused_names + continue unless pos names_by_position[pos] or= {} insert names_by_position[pos], name @@ -127,6 +133,7 @@ class LinterBlock extends Block .render = @render .get_root_block = @get_root_block .lint_check_unused = @lint_check_unused + .lint_mark_used = @lint_mark_used .value_compilers = @value_compilers .statement_compilers = @statement_compilers From 2d5dd107d47e3d86885a87ac3158d23ab9be48fb Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 28 Feb 2015 11:47:58 -0800 Subject: [PATCH 245/554] fix opts passing to cmd.moonc --- bin/moonc | 7 ++++++- moonscript/cmd/moonc.lua | 4 ++-- moonscript/cmd/moonc.moon | 4 ++-- spec/cmd_spec.moon | 2 +- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/bin/moonc b/bin/moonc index 4dfd2358..bc8ed20b 100755 --- a/bin/moonc +++ b/bin/moonc @@ -315,8 +315,13 @@ else end local success, err = compile_and_write(fname, target, { - print = opts.p + print = opts.p, + fname = fname, + benchmark = opts.b, + show_posmap = opts.X, + show_parse_tree = opts.T, }) + if not success then io.stderr:write(fname .. "\t" .. err .. "\n") os.exit(1) diff --git a/moonscript/cmd/moonc.lua b/moonscript/cmd/moonc.lua index b64c9f1c..c21cbdd8 100644 --- a/moonscript/cmd/moonc.lua +++ b/moonscript/cmd/moonc.lua @@ -55,7 +55,7 @@ do end end end -compile_file_text = function(text, fname, opts) +compile_file_text = function(text, opts) if opts == nil then opts = { } end @@ -97,7 +97,7 @@ compile_file_text = function(text, fname, opts) end if opts.benchmark then print(table.concat({ - fname, + opts.fname or "stdin", "Parse time \t" .. format_time(parse_time), "Compile time\t" .. format_time(compile_time), "" diff --git a/moonscript/cmd/moonc.moon b/moonscript/cmd/moonc.moon index 6b8b206b..ee81eb20 100644 --- a/moonscript/cmd/moonc.moon +++ b/moonscript/cmd/moonc.moon @@ -63,7 +63,7 @@ gettime = do -- compiles file to lua, returns lua code -- returns nil, error on error -- returns true if some option handled the output instead -compile_file_text = (text, fname, opts={}) -> +compile_file_text = (text, opts={}) -> parse = require "moonscript.parse" compile = require "moonscript.compile" @@ -100,7 +100,7 @@ compile_file_text = (text, fname, opts={}) -> if opts.benchmark print table.concat { - fname, + opts.fname or "stdin", "Parse time \t" .. format_time(parse_time), "Compile time\t" .. format_time(compile_time), "" diff --git a/spec/cmd_spec.moon b/spec/cmd_spec.moon index 3ac5dea0..84012e31 100644 --- a/spec/cmd_spec.moon +++ b/spec/cmd_spec.moon @@ -55,7 +55,7 @@ describe "moonc", -> assert.same { [[return print('hello')]] }, { - moonc.compile_file_text "print'hello'", "test.moon" + moonc.compile_file_text "print'hello'", fname: "test.moon" } describe "stubbed lfs", -> From 09a2a5c54588dbfa3454509023c5023517a8611a Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 28 Feb 2015 11:52:14 -0800 Subject: [PATCH 246/554] mark position of table self assigns to not confuse linter --- moonscript/cmd/lint.lua | 2 +- moonscript/cmd/lint.moon | 2 +- moonscript/parse.lua | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/moonscript/cmd/lint.lua b/moonscript/cmd/lint.lua index 1fd80b05..52dba4e0 100644 --- a/moonscript/cmd/lint.lua +++ b/moonscript/cmd/lint.lua @@ -167,7 +167,7 @@ do local sc = self.statement_compilers self.statement_compilers = setmetatable({ assign = function(block, node) - local _, names, values = unpack(node) + local names = node[2] for _index_0 = 1, #names do local _continue_0 = false repeat diff --git a/moonscript/cmd/lint.moon b/moonscript/cmd/lint.moon index 8317e5c5..103c25ed 100644 --- a/moonscript/cmd/lint.moon +++ b/moonscript/cmd/lint.moon @@ -76,7 +76,7 @@ class LinterBlock extends Block sc = @statement_compilers @statement_compilers = setmetatable { assign: (block, node) -> - _, names, values = unpack node + names = node[2] -- extract the names to be declared for name in *names -- don't include autogenerated names diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 63458592..b26562d7 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -277,8 +277,8 @@ local function check_lua_string(str, pos, right, left) end -- :name in table literal -local function self_assign(name) - return {{"key_literal", name}, name} +local function self_assign(name, pos) + return {{"key_literal", name}, {"ref", name, [-1] = pos}} end local err_msg = "Failed to parse:%s\n [%d] >> %s" @@ -552,7 +552,7 @@ local build_grammar = wrap_env(function() op"*" + op"^" + Ct(NameList) * (sym"=" * Ct(ExpListLow))^-1) / mark"export", - KeyValue = (sym":" * -SomeSpace * Name) / self_assign + Ct((KeyName + sym"[" * Exp * sym"]" + DoubleString + SingleString) * symx":" * (Exp + TableBlock)), + KeyValue = (sym":" * -SomeSpace * Name * lpeg.Cp()) / self_assign + Ct((KeyName + sym"[" * Exp * sym"]" + DoubleString + SingleString) * symx":" * (Exp + TableBlock)), KeyValueList = KeyValue * (sym"," * KeyValue)^0, KeyValueLine = CheckIndent * KeyValueList * sym","^-1, From 9a3504afc267fd709e24d003875eba769327a10d Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 28 Feb 2015 11:53:47 -0800 Subject: [PATCH 247/554] lint --- moonscript/cmd/moonc.lua | 1 - moonscript/cmd/moonc.moon | 1 - 2 files changed, 2 deletions(-) diff --git a/moonscript/cmd/moonc.lua b/moonscript/cmd/moonc.lua index c21cbdd8..eae86380 100644 --- a/moonscript/cmd/moonc.lua +++ b/moonscript/cmd/moonc.lua @@ -182,7 +182,6 @@ return { normalize_dir = normalize_dir, parse_dir = parse_dir, parse_file = parse_file, - new_path = new_path, convert_path = convert_path, gettime = gettime, format_time = format_time, diff --git a/moonscript/cmd/moonc.moon b/moonscript/cmd/moonc.moon index ee81eb20..a680eaa7 100644 --- a/moonscript/cmd/moonc.moon +++ b/moonscript/cmd/moonc.moon @@ -182,7 +182,6 @@ path_to_target = (path, target_dir=nil, base_dir=nil) -> :normalize_dir :parse_dir :parse_file - :new_path :convert_path :gettime :format_time From 64ac22aa7b545b88ec366594b7142d33c6a00385 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 28 Feb 2015 12:42:36 -0800 Subject: [PATCH 248/554] docs for new lint functionality --- docs/command_line.md | 46 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/docs/command_line.md b/docs/command_line.md index a68e3485..aac3e7bd 100644 --- a/docs/command_line.md +++ b/docs/command_line.md @@ -131,9 +131,9 @@ A full list of flags can be seen by passing the `-h` or `--help` flag. ### Linter -`moonc` contains a [lint][1] tool -for statically detecting potential problems with code. The current linter only -has one test: it detects the use of global variables. +`moonc` contains a [lint][1] tool for statically detecting potential problems +with code. The linter has two tests: detects accessed global variables, +detect unused declared variables. You can execute the linter with the `-l` flag. When the linting flag is provided only linting takes place and no compiled code is generated. @@ -184,7 +184,7 @@ Outputs: ./lint_example.moon - line 7: accessing global my_nmuber + line 7: accessing global `my_nmuber` ================================== > my_nmuber + 10 @@ -245,6 +245,44 @@ that are allowed. Multiple patterns in `whitelist_globals` can match a single file, the union of the allowed globals will be used when linting that file. +#### Unused Variable Assigns + +Sometimes when debugging, refactoring, or just developing, you might leave +behind stray assignments that aren't actually necessary for the execution of +your code. It's good practice to clean them up to avoid any potential confusion +they might cause. + +The unused assignment detector keeps track of any variables that are assigned, +and if they aren't accessed in within their available scope, they are reported +as an error. + +Given the following code: + +```moononly +a, b = 1, 2 +print "hello", a +``` + +The linter will identify the problem: + + ./lint_example.moon + + line 1: assigned but unused `b` + =============================== + > a, b = 1, 2 + + +Sometimes you need a name to assign to even though you know it will never be +accessed. The linter will treat `_` as a special name that's allowed to be +written to but never accessed: + +The following code would not produce any lint errors: + +```moononly +item = {123, "shoe", "brown", 123} +_, name, _, count = unpack item +print name, count +``` [1]: http://en.wikipedia.org/wiki/Lint_(software) From 72615aa6e226d3acfc9a24e6a7acb860cff62542 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 28 Feb 2015 12:47:21 -0800 Subject: [PATCH 249/554] date and doc misc updates --- README.md | 5 +++-- docs/reference.md | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 31d2f52d..5b2b555c 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,8 @@ MoonScript is a programmer friendly language that compiles into [Lua](http://www.lua.org/). It gives you the power of the fastest scripting -language combined with a rich set of features. It runs on Lua 5.1 and 5.2. +language combined with a rich set of features. It runs on Lua 5.1 and above, +including alternative runtimes like LuaJIT. See . @@ -25,7 +26,7 @@ busted ## License (MIT) -Copyright (C) 2013 by Leaf Corcoran +Copyright (C) 2015 by Leaf Corcoran Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/docs/reference.md b/docs/reference.md index a67fd332..3a8e9872 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -1558,7 +1558,7 @@ their written order you can add `local *` to the top of your file. # License (MIT) - Copyright (C) 2014 by Leaf Corcoran + Copyright (C) 2015 by Leaf Corcoran Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 8ea934964aecbeba9343129861386daa91d1ee22 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 28 Feb 2015 13:26:29 -0800 Subject: [PATCH 250/554] allow whitespace/newlines after binary operator --- moonscript/parse.lua | 10 +++------- spec/inputs/operators.moon | 33 +++++++++++++++++++++++++++++++++ spec/outputs/operators.lua | 13 +++++++++++++ 3 files changed, 49 insertions(+), 7 deletions(-) create mode 100644 spec/inputs/operators.moon create mode 100644 spec/outputs/operators.lua diff --git a/moonscript/parse.lua b/moonscript/parse.lua index b26562d7..726dda71 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -436,16 +436,12 @@ local build_grammar = wrap_env(function() 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", - -- we can ignore precedence for now + -- we don't need to parse precedence, lua will handle it for us OtherOps = op"or" + op"and" + op"<=" + op">=" + op"~=" + op"!=" + op"==" + op".." + op"<" + op">", + BinaryOperator = (OtherOps + FactorOp + TermOp) * SpaceBreak^0, Assignable = Cmt(DotChain + Chain, check_assignable) + Name + SelfName, - - Exp = Ct(Value * ((OtherOps + FactorOp + TermOp) * Value)^0) / flatten_or_mark"exp", - - -- Exp = Ct(Factor * (OtherOps * Factor)^0) / flatten_or_mark"exp", - -- Factor = Ct(Term * (FactorOp * Term)^0) / flatten_or_mark"exp", - -- Term = Ct(Value * (TermOp * Value)^0) / flatten_or_mark"exp", + Exp = Ct(Value * (BinaryOperator * Value)^0) / flatten_or_mark"exp", SimpleValue = If + Unless + diff --git a/spec/inputs/operators.moon b/spec/inputs/operators.moon new file mode 100644 index 00000000..742ad7f5 --- /dev/null +++ b/spec/inputs/operators.moon @@ -0,0 +1,33 @@ + +-- +x = 1 + 3 + +y = 1 + + 3 + +z = 1 + + 3 + + 4 + +-- + +k = b and c and + g + + +h = thing and + -> + print "hello world" + +-- TODO: should fail, indent still set to previous line so it thinks body is +-- indented +i = thing or + -> + print "hello world" + +p = thing and + -> +print "hello world" + +s = thing or + -> and 234 diff --git a/spec/outputs/operators.lua b/spec/outputs/operators.lua new file mode 100644 index 00000000..2c2a956c --- /dev/null +++ b/spec/outputs/operators.lua @@ -0,0 +1,13 @@ +local x = 1 + 3 +local y = 1 + 3 +local z = 1 + 3 + 4 +local k = b and c and g +local h = thing and function() + return print("hello world") +end +local i = thing or function() + return print("hello world") +end +local p = thing and function() end +print("hello world") +local s = thing or function() end and 234 \ No newline at end of file From 1982b565d86e1fdc2ba2a217c802389c01c170a2 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 28 Feb 2015 13:36:52 -0800 Subject: [PATCH 251/554] refactor operators parsing --- moonscript/parse.lua | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 726dda71..e150c79e 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -59,9 +59,6 @@ local Num = P"0x" * R("09", "af", "AF")^1 * (S"uU"^-1 * S"lL"^2)^-1 + Num = Space * (Num / function(value) return {"number", value} end) -local FactorOp = Space * C(S"+-") -local TermOp = Space * C(S"*/%^") - local Shebang = P"#!" * P(1 - Stop)^0 -- can't have P(false) because it causes preceding patterns not to run @@ -436,9 +433,9 @@ local build_grammar = wrap_env(function() 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", - -- we don't need to parse precedence, lua will handle it for us - OtherOps = op"or" + op"and" + op"<=" + op">=" + op"~=" + op"!=" + op"==" + op".." + op"<" + op">", - BinaryOperator = (OtherOps + FactorOp + TermOp) * SpaceBreak^0, + CharOperators = Space * C(S"+-*/%^><"), + WordOperators = op"or" + op"and" + op"<=" + op">=" + op"~=" + op"!=" + op"==" + op"..", + BinaryOperator = (WordOperators + CharOperators) * SpaceBreak^0, Assignable = Cmt(DotChain + Chain, check_assignable) + Name + SelfName, Exp = Ct(Value * (BinaryOperator * Value)^0) / flatten_or_mark"exp", From e61c2ba29f042d9b1a35b3e7ab736461c7f96bba Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 28 Feb 2015 13:41:38 -0800 Subject: [PATCH 252/554] spacebreak operator tests in more places --- spec/inputs/operators.moon | 17 +++++++++++++++++ spec/outputs/operators.lua | 13 ++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/spec/inputs/operators.moon b/spec/inputs/operators.moon index 742ad7f5..d090865d 100644 --- a/spec/inputs/operators.moon +++ b/spec/inputs/operators.moon @@ -31,3 +31,20 @@ print "hello world" s = thing or -> and 234 + + +-- +u = { + color: 1 and 2 and + 3 + 4 + 4 +} + +v = { + color: 1 and + -> + "yeah" + "great" +} + diff --git a/spec/outputs/operators.lua b/spec/outputs/operators.lua index 2c2a956c..95a10751 100644 --- a/spec/outputs/operators.lua +++ b/spec/outputs/operators.lua @@ -10,4 +10,15 @@ local i = thing or function() end local p = thing and function() end print("hello world") -local s = thing or function() end and 234 \ No newline at end of file +local s = thing or function() end and 234 +local u = { + color = 1 and 2 and 3, + 4, + 4 +} +local v = { + color = 1 and function() + return "yeah" + end, + "great" +} \ No newline at end of file From 7109da7e1db12973a5c19fbfc6a2e4a08b4b1030 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 28 Feb 2015 13:52:09 -0800 Subject: [PATCH 253/554] parens can take spacebreaks on the insides of either side --- moonscript/parse.lua | 5 +++-- spec/inputs/operators.moon | 24 +++++++++++++++++++++++- spec/outputs/operators.lua | 9 +++++++-- 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/moonscript/parse.lua b/moonscript/parse.lua index e150c79e..0da86c62 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -216,6 +216,7 @@ local function sym(chars) return Space * chars end +-- Like sym but doesn't accept whitespace in front local function symx(chars) return chars end @@ -482,9 +483,9 @@ local build_grammar = wrap_env(function() LuaStringClose = "]" * P"="^0 * "]", Callable = pos(Name / mark"ref") + SelfName + VarArg + Parens / mark"parens", - Parens = sym"(" * Exp * sym")", + Parens = sym"(" * SpaceBreak^0 * Exp * SpaceBreak^0 * sym")", - FnArgs = symx"(" * Ct(ExpList^-1) * sym")" + sym"!" * -P"=" * Ct"", + FnArgs = symx"(" * SpaceBreak^0 * Ct(ExpList^-1) * SpaceBreak^0 * sym")" + sym"!" * -P"=" * Ct"", ChainTail = ChainItem^1 * ColonSuffix^-1 + ColonSuffix, diff --git a/spec/inputs/operators.moon b/spec/inputs/operators.moon index d090865d..142ef622 100644 --- a/spec/inputs/operators.moon +++ b/spec/inputs/operators.moon @@ -1,5 +1,5 @@ --- +-- binary ops x = 1 + 3 y = 1 + @@ -46,5 +46,27 @@ v = { -> "yeah" "great" + oksy: 3 ^ +2 } +-- parens + +nno = ( + yeah + 2 ) + +nn = ( + yeah + 2 +) + +n = hello( + b +) -> + +hello a, + ( + yeah + + 2 + ) - + okay + diff --git a/spec/outputs/operators.lua b/spec/outputs/operators.lua index 95a10751..9829ef57 100644 --- a/spec/outputs/operators.lua +++ b/spec/outputs/operators.lua @@ -20,5 +20,10 @@ local v = { color = 1 and function() return "yeah" end, - "great" -} \ No newline at end of file + "great", + oksy = 3 ^ 2 +} +local nno = (yeah + 2) +local nn = (yeah + 2) +local n = hello(b)(function() end) +return hello(a, (yeah + 2) - okay) \ No newline at end of file From 5e162e22a569b5798170c9688d556b0c900880e0 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 28 Feb 2015 14:08:44 -0800 Subject: [PATCH 254/554] spacebreak can come after table colon --- moonscript/parse.lua | 2 +- spec/inputs/tables.moon | 25 +++++++++++++++++++++++++ spec/outputs/tables.lua | 34 +++++++++++++++++++++++++++++++++- 3 files changed, 59 insertions(+), 2 deletions(-) diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 0da86c62..2780a67f 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -546,7 +546,7 @@ local build_grammar = wrap_env(function() op"*" + op"^" + Ct(NameList) * (sym"=" * Ct(ExpListLow))^-1) / mark"export", - KeyValue = (sym":" * -SomeSpace * Name * lpeg.Cp()) / self_assign + Ct((KeyName + sym"[" * Exp * sym"]" + DoubleString + SingleString) * symx":" * (Exp + TableBlock)), + KeyValue = (sym":" * -SomeSpace * Name * lpeg.Cp()) / self_assign + Ct((KeyName + sym"[" * Exp * sym"]" + DoubleString + SingleString) * symx":" * (Exp + TableBlock + SpaceBreak^1 * Exp)), KeyValueList = KeyValue * (sym"," * KeyValue)^0, KeyValueLine = CheckIndent * KeyValueList * sym","^-1, diff --git a/spec/inputs/tables.moon b/spec/inputs/tables.moon index e918556f..0c2a697f 100644 --- a/spec/inputs/tables.moon +++ b/spec/inputs/tables.moon @@ -102,3 +102,28 @@ xam = { } +kam = { + hello: 12 + goodcheese: + "mmm" + + yeah: + 12 + 232 + + lets: + keepit going: true, + okay: "yeah" + + more: + { + 1, [x for x=1,10] + } + + [{"one", "two"}]: + one_thing => +} + +keepit going: true, + okay: "yeah", + workd: "okay" + diff --git a/spec/outputs/tables.lua b/spec/outputs/tables.lua index 7eabec1c..cb6ff9f9 100644 --- a/spec/outputs/tables.lua +++ b/spec/outputs/tables.lua @@ -125,4 +125,36 @@ local xam = { hello = 1234, ["hello"] = 12354, ["hello"] = 12354 -} \ No newline at end of file +} +local kam = { + hello = 12, + goodcheese = "mmm", + yeah = 12 + 232, + lets = keepit({ + going = true + }, { + okay = "yeah" + }), + more = { + 1, + (function() + local _accum_0 = { } + local _len_0 = 1 + for x = 1, 10 do + _accum_0[_len_0] = x + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + }, + [{ + "one", + "two" + }] = one_thing(function(self) end) +} +return keepit({ + going = true +}, { + okay = "yeah", + workd = "okay" +}) \ No newline at end of file From adccbadf183cbfc0ae29aa2d11d4dbf62dc9d5f9 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 28 Feb 2015 14:10:45 -0800 Subject: [PATCH 255/554] more whitespace sepcs for table --- spec/inputs/tables.moon | 14 ++++++++++++++ spec/outputs/tables.lua | 18 ++++++++++++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/spec/inputs/tables.moon b/spec/inputs/tables.moon index 0c2a697f..3dad4124 100644 --- a/spec/inputs/tables.moon +++ b/spec/inputs/tables.moon @@ -123,7 +123,21 @@ kam = { one_thing => } +-- TODO: both of these have undesirable output keepit going: true, okay: "yeah", workd: "okay" +thing what: + "great", no: + "more" + okay: 123 + + +-- +thing what: + "great", no: + "more" +okay: 123 -- a anon table + +nil diff --git a/spec/outputs/tables.lua b/spec/outputs/tables.lua index cb6ff9f9..0cad58a5 100644 --- a/spec/outputs/tables.lua +++ b/spec/outputs/tables.lua @@ -152,9 +152,23 @@ local kam = { "two" }] = one_thing(function(self) end) } -return keepit({ +keepit({ going = true }, { okay = "yeah", workd = "okay" -}) \ No newline at end of file +}) +thing({ + what = "great", + no = "more" +}, { + okay = 123 +}) +thing({ + what = "great", + no = "more" +}) +local _ = { + okay = 123 +} +return nil \ No newline at end of file From b9013efcdccfbf862b304fb7723be5a3953e3053 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 28 Feb 2015 14:48:25 -0800 Subject: [PATCH 256/554] parse.literals module --- Makefile | 5 ++- moonscript/parse.lua | 59 +++++++++++++--------------------- moonscript/parse/literals.lua | 34 ++++++++++++++++++++ moonscript/parse/literals.moon | 34 ++++++++++++++++++++ moonscript/util.lua | 11 ++++++- moonscript/util.moon | 8 ++++- 6 files changed, 112 insertions(+), 39 deletions(-) create mode 100644 moonscript/parse/literals.lua create mode 100644 moonscript/parse/literals.moon diff --git a/Makefile b/Makefile index 4781fa3a..9a44cfec 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,11 @@ -.PHONY: test local compile watch lint +.PHONY: test local compile watch lint test_safe test: busted -p "_spec.moon$$" +test_safe: + busted -p "_spec.lua$$" + local: compile luarocks make --local moonscript-dev-1.rockspec diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 2780a67f..427fb857 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -1,15 +1,15 @@ - -local util = require"moonscript.util" +local debug_grammar = false local lpeg = require"lpeg" -local debug_grammar = false +lpeg.setmaxstack(10000) +local util = require"moonscript.util" local data = require"moonscript.data" local types = require"moonscript.types" +local literals = require "moonscript.parse.literals" local ntype = types.ntype - local trim = util.trim local getfenv = util.getfenv @@ -18,6 +18,25 @@ local unpack = util.unpack local Stack = data.Stack +local R, S, V, P = lpeg.R, lpeg.S, lpeg.V, lpeg.P +local C, Ct, Cmt, Cg, Cb, Cc = lpeg.C, lpeg.Ct, lpeg.Cmt, lpeg.Cg, lpeg.Cb, lpeg.Cc + +local White = literals.White +local Break = literals.Break +local Stop = literals.Stop +local Comment = literals.Comment +local Space = literals.Space +local SomeSpace = literals.SomeSpace +local SpaceBreak = literals.SpaceBreak +local EmptyLine = literals.EmptyLine +local AlphaNum = literals.AlphaNum +local _Name = literals.Name +local Num = literals.Num +local Shebang = literals.Shebang + +local Name = Space * _Name +Num = Space * (Num / function(value) return {"number", value} end) + local function count_indent(str) local sum = 0 for v in str:gmatch("[\t ]") do @@ -27,40 +46,8 @@ local function count_indent(str) return sum end -local R, S, V, P = lpeg.R, lpeg.S, lpeg.V, lpeg.P -local C, Ct, Cmt, Cg, Cb, Cc = lpeg.C, lpeg.Ct, lpeg.Cmt, lpeg.Cg, lpeg.Cb, lpeg.Cc - -lpeg.setmaxstack(10000) - -local White = S" \t\r\n"^0 -local _Space = S" \t"^0 -local Break = P"\r"^-1 * P"\n" -local Stop = Break + -1 local Indent = C(S"\t "^0) / count_indent -local Comment = P"--" * (1 - S"\r\n")^0 * #Stop -local Space = _Space * Comment^-1 -local SomeSpace = S" \t"^1 * Comment^-1 - -local SpaceBreak = Space * Break -local EmptyLine = SpaceBreak - -local AlphaNum = R("az", "AZ", "09", "__") - -local _Name = C(R("az", "AZ", "__") * AlphaNum^0) -local Name = Space * _Name - -local Num = P"0x" * R("09", "af", "AF")^1 * (S"uU"^-1 * S"lL"^2)^-1 + - R"09"^1 * (S"uU"^-1 * S"lL"^2) + - ( - R"09"^1 * (P"." * R"09"^1)^-1 + - P"." * R"09"^1 - ) * (S"eE" * P"-"^-1 * R"09"^1)^-1 - -Num = Space * (Num / function(value) return {"number", value} end) - -local Shebang = P"#!" * P(1 - Stop)^0 - -- can't have P(false) because it causes preceding patterns not to run local Cut = P(function() return false end) diff --git a/moonscript/parse/literals.lua b/moonscript/parse/literals.lua new file mode 100644 index 00000000..61d6e2b8 --- /dev/null +++ b/moonscript/parse/literals.lua @@ -0,0 +1,34 @@ +local safe_module +safe_module = require("moonscript.util").safe_module +local S, P, R, C +do + local _obj_0 = require("lpeg") + S, P, R, C = _obj_0.S, _obj_0.P, _obj_0.R, _obj_0.C +end +local White = S(" \t\r\n") ^ 0 +local plain_space = S(" \t") ^ 0 +local Break = P("\r") ^ -1 * P("\n") +local Stop = Break + -1 +local Comment = P("--") * (1 - S("\r\n")) ^ 0 * #Stop +local Space = plain_space * Comment ^ -1 +local SomeSpace = S(" \t") ^ 1 * Comment ^ -1 +local SpaceBreak = Space * Break +local EmptyLine = SpaceBreak +local AlphaNum = R("az", "AZ", "09", "__") +local Name = C(R("az", "AZ", "__") * AlphaNum ^ 0) +local Num = P("0x") * R("09", "af", "AF") ^ 1 * (S("uU") ^ -1 * S("lL") ^ 2) ^ -1 + R("09") ^ 1 * (S("uU") ^ -1 * S("lL") ^ 2) + (R("09") ^ 1 * (P(".") * R("09") ^ 1) ^ -1 + P(".") * R("09") ^ 1) * (S("eE") * P("-") ^ -1 * R("09") ^ 1) ^ -1 +local Shebang = P("#!") * P(1 - Stop) ^ 0 +return safe_module("moonscript.parse.literals", { + White = White, + Break = Break, + Stop = Stop, + Comment = Comment, + Space = Space, + SomeSpace = SomeSpace, + SpaceBreak = SpaceBreak, + EmptyLine = EmptyLine, + AlphaNum = AlphaNum, + Name = Name, + Num = Num, + Shebang = Shebang +}) diff --git a/moonscript/parse/literals.moon b/moonscript/parse/literals.moon new file mode 100644 index 00000000..8f0d8cd6 --- /dev/null +++ b/moonscript/parse/literals.moon @@ -0,0 +1,34 @@ +-- non-recursive parsers +import safe_module from require "moonscript.util" +import S, P, R, C from require "lpeg" + +White = S" \t\r\n"^0 +plain_space = S" \t"^0 + +Break = P"\r"^-1 * P"\n" +Stop = Break + -1 + +Comment = P"--" * (1 - S"\r\n")^0 * #Stop +Space = plain_space * Comment^-1 +SomeSpace = S" \t"^1 * Comment^-1 + +SpaceBreak = Space * Break +EmptyLine = SpaceBreak + +AlphaNum = R "az", "AZ", "09", "__" + +Name = C R("az", "AZ", "__") * AlphaNum^0 + +Num = P"0x" * R("09", "af", "AF")^1 * (S"uU"^-1 * S"lL"^2)^-1 + + R"09"^1 * (S"uU"^-1 * S"lL"^2) + + ( + R"09"^1 * (P"." * R"09"^1)^-1 + + P"." * R"09"^1 + ) * (S"eE" * P"-"^-1 * R"09"^1)^-1 + +Shebang = P"#!" * P(1 - Stop)^0 + +safe_module "moonscript.parse.literals", { + :White, :Break, :Stop, :Comment, :Space, :SomeSpace, :SpaceBreak, :EmptyLine, + :AlphaNum, :Name, :Num, :Shebang +} diff --git a/moonscript/util.lua b/moonscript/util.lua index 7eddae37..cc41ebc3 100644 --- a/moonscript/util.lua +++ b/moonscript/util.lua @@ -196,6 +196,14 @@ get_options = function(...) return { }, ... end end +local safe_module +safe_module = function(name, tbl) + return setmetatable(tbl, { + __index = function(self, key) + return error("Attempted to import non-existent `" .. tostring(key) .. "` from " .. tostring(name)) + end + }) +end return { moon = moon, pos_to_line = pos_to_line, @@ -209,5 +217,6 @@ return { getfenv = getfenv, setfenv = setfenv, get_options = get_options, - unpack = unpack + unpack = unpack, + safe_module = safe_module } diff --git a/moonscript/util.moon b/moonscript/util.moon index d43d0505..8df3b538 100644 --- a/moonscript/util.moon +++ b/moonscript/util.moon @@ -129,8 +129,14 @@ get_options = (...) -> else {}, ... +safe_module = (name, tbl) -> + setmetatable tbl, { + __index: (key) => + error "Attempted to import non-existent `#{key}` from #{name}" + } + { :moon, :pos_to_line, :get_closest_line, :get_line, :reversed, :trim, :split, - :dump, :debug_posmap, :getfenv, :setfenv, :get_options, :unpack + :dump, :debug_posmap, :getfenv, :setfenv, :get_options, :unpack, :safe_module } From 5b0df1cd623c5a34f092071bd30bdafa2b2a3aa0 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 28 Feb 2015 15:01:28 -0800 Subject: [PATCH 257/554] wrap_env in moonscript, separate module --- moonscript/parse.lua | 58 ++------------------------------ moonscript/parse/env.lua | 70 +++++++++++++++++++++++++++++++++++++++ moonscript/parse/env.moon | 50 ++++++++++++++++++++++++++++ 3 files changed, 123 insertions(+), 55 deletions(-) create mode 100644 moonscript/parse/env.lua create mode 100644 moonscript/parse/env.moon diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 427fb857..f8a1a441 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -12,8 +12,8 @@ local literals = require "moonscript.parse.literals" local ntype = types.ntype local trim = util.trim -local getfenv = util.getfenv -local setfenv = util.setfenv +local wrap_env = require("moonscript.parse.env").wrap_env + local unpack = util.unpack local Stack = data.Stack @@ -55,58 +55,6 @@ local function ensure(patt, finally) return patt * finally + finally * Cut end --- auto declare Proper variables with lpeg.V -local function wrap_env(fn) - local env = getfenv(fn) - local wrap_name = V - - if debug_grammar then - local indent = 0 - local indent_char = " " - - local function iprint(...) - local args = {...} - for i=1,#args do - args[i] = tostring(args[i]) - end - - io.stdout:write(indent_char:rep(indent) .. table.concat(args, ", ") .. "\n") - end - - wrap_name = function(name) - local v = V(name) - v = Cmt("", function() - iprint("* " .. name) - indent = indent + 1 - return true - end) * Cmt(v, function(str, pos, ...) - iprint(name, true) - indent = indent - 1 - return true, ... - end) + Cmt("", function() - iprint(name, false) - indent = indent - 1 - return false - end) - return v - end - end - - return setfenv(fn, setmetatable({}, { - __index = function(self, name) - local value = env[name] - if value ~= nil then return value end - - if name:match"^[A-Z][A-Za-z0-9]*$" then - local v = wrap_name(name) - rawset(self, name, v) - return v - end - error("unknown variable referenced: "..name) - end - })) -end - local function extract_line(str, start_pos) str = str:sub(start_pos) local m = str:match"^(.-)\n" @@ -268,7 +216,7 @@ end local err_msg = "Failed to parse:%s\n [%d] >> %s" -local build_grammar = wrap_env(function() +local build_grammar = wrap_env(debug_grammar, function() local _indent = Stack(0) -- current indent local _do_stack = Stack(0) diff --git a/moonscript/parse/env.lua b/moonscript/parse/env.lua new file mode 100644 index 00000000..4a0adc33 --- /dev/null +++ b/moonscript/parse/env.lua @@ -0,0 +1,70 @@ +local getfenv, setfenv +do + local _obj_0 = require("moonscript.util") + getfenv, setfenv = _obj_0.getfenv, _obj_0.setfenv +end +local wrap_env +wrap_env = function(debug, fn) + local V, Cmt + do + local _obj_0 = require("lpeg") + V, Cmt = _obj_0.V, _obj_0.Cmt + end + local env = getfenv(fn) + local wrap_name = V + if debug then + local indent = 0 + local indent_char = " " + local iprint + iprint = function(...) + local args = table.concat((function(...) + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local a = _list_0[_index_0] + _accum_0[_len_0] = tostring(a) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)(...), ", ") + return io.stderr:write(tostring(indent_char:rep(indent)) .. tostring(args) .. "\n") + end + wrap_name = function(name) + local v = V(name) + v = Cmt("", function() + iprint("* " .. name) + indent = indent + 1 + return true + end) * Cmt(v, function(str, pos, ...) + iprint(name, true) + indent = indent - 1 + return true, ... + end) + Cmt("", function() + iprint(name, false) + indent = indent - 1 + return false + end) + return v + end + end + return setfenv(fn, setmetatable({ }, { + __index = function(self, name) + local value = env[name] + if value ~= nil then + return value + end + if name:match("^[A-Z][A-Za-z0-9]*$") then + local v = wrap_name(name) + rawset(self, name, v) + return v + end + return error("unknown variable referenced: " .. tostring(name)) + end + })) +end +return { + wrap_env = wrap_env +} diff --git a/moonscript/parse/env.moon b/moonscript/parse/env.moon new file mode 100644 index 00000000..594d3e59 --- /dev/null +++ b/moonscript/parse/env.moon @@ -0,0 +1,50 @@ + +import getfenv, setfenv from require "moonscript.util" + +-- all undefined Proper globals are automaticlly converted into lpeg.V +wrap_env = (debug, fn) -> + import V, Cmt from require "lpeg" + + env = getfenv fn + wrap_name = V + + if debug + indent = 0 + indent_char = " " + + iprint = (...) -> + args = table.concat [tostring a for a in *{...}], ", " + io.stderr\write "#{indent_char\rep(indent)}#{args}\n" + + wrap_name = (name) -> + v = V name + v = Cmt("", -> + iprint "* " .. name + indent += 1 + true + ) * Cmt(v, (str, pos, ...) -> + iprint name, true + indent -= 1 + true, ... + ) + Cmt("", -> + iprint name, false + indent -= 1 + false + ) + + v + + setfenv fn, setmetatable {}, { + __index: (name) => + value = env[name] + return value if value != nil + + if name\match"^[A-Z][A-Za-z0-9]*$" + v = wrap_name name + rawset @, name, v + return v + + error "unknown variable referenced: #{name}" + } + +{ :wrap_env } From 72d496dd667fcb8b8aaa7d5ffb809bf38e2915e9 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 28 Feb 2015 15:12:27 -0800 Subject: [PATCH 258/554] start moving parse helpers to moonscript --- moonscript/parse.lua | 21 ++++----------------- moonscript/parse/util.lua | 31 +++++++++++++++++++++++++++++++ moonscript/parse/util.moon | 23 +++++++++++++++++++++++ 3 files changed, 58 insertions(+), 17 deletions(-) create mode 100644 moonscript/parse/util.lua create mode 100644 moonscript/parse/util.moon diff --git a/moonscript/parse.lua b/moonscript/parse.lua index f8a1a441..4f7ec894 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -8,6 +8,7 @@ local util = require"moonscript.util" local data = require"moonscript.data" local types = require"moonscript.types" local literals = require "moonscript.parse.literals" +local parse_util = require "moonscript.parse.util" local ntype = types.ntype local trim = util.trim @@ -37,23 +38,9 @@ local Shebang = literals.Shebang local Name = Space * _Name Num = Space * (Num / function(value) return {"number", value} end) -local function count_indent(str) - local sum = 0 - for v in str:gmatch("[\t ]") do - if v == ' ' then sum = sum + 1 end - if v == '\t' then sum = sum + 4 end - end - return sum -end - -local Indent = C(S"\t "^0) / count_indent - --- can't have P(false) because it causes preceding patterns not to run -local Cut = P(function() return false end) - -local function ensure(patt, finally) - return patt * finally + finally * Cut -end +local Indent = parse_util.Indent +local Cut = parse_util.Cut +local ensure = parse_util.ensure local function extract_line(str, start_pos) str = str:sub(start_pos) diff --git a/moonscript/parse/util.lua b/moonscript/parse/util.lua new file mode 100644 index 00000000..81a4ca9f --- /dev/null +++ b/moonscript/parse/util.lua @@ -0,0 +1,31 @@ +local P, C, S +do + local _obj_0 = require("lpeg") + P, C, S = _obj_0.P, _obj_0.C, _obj_0.S +end +local Indent = C(S("\t ") ^ 0) / function(str) + do + local sum = 0 + for v in str:gmatch("[\t ]") do + local _exp_0 = v + if " " == _exp_0 then + sum = sum + 1 + elseif "\t" == _exp_0 then + sum = sum + 4 + end + end + return sum + end +end +local Cut = P(function() + return false +end) +local ensure +ensure = function(patt, finally) + return patt * finally + finally * Cut +end +return { + Indent = Indent, + Cut = Cut, + ensure = ensure +} diff --git a/moonscript/parse/util.moon b/moonscript/parse/util.moon new file mode 100644 index 00000000..f10dda99 --- /dev/null +++ b/moonscript/parse/util.moon @@ -0,0 +1,23 @@ + +import P, C, S from require "lpeg" + +-- captures an indentation, returns indent depth +Indent = C(S"\t "^0) / (str) -> + with sum = 0 + for v in str\gmatch "[\t ]" + switch v + when " " + sum += 1 + when "\t" + sum += 4 + + +-- causes pattern in progress to be rejected +-- can't have P(false) because it causes preceding patterns not to run +Cut = P -> false + +-- ensures finally runs regardless of whether pattern fails or passes +ensure = (patt, finally) -> + patt * finally + finally * Cut + +{ :Indent, :Cut, :ensure } From a1d9e39caa4a538cc5558d64f611f63ea430f4c2 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 28 Feb 2015 16:01:52 -0800 Subject: [PATCH 259/554] convert rest of parse helpers to moonscript --- moonscript/parse.lua | 177 +++------------------------ moonscript/parse/util.lua | 242 ++++++++++++++++++++++++++++++++++++- moonscript/parse/util.moon | 150 ++++++++++++++++++++++- 3 files changed, 404 insertions(+), 165 deletions(-) diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 4f7ec894..af5398cb 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -41,165 +41,24 @@ Num = Space * (Num / function(value) return {"number", value} end) local Indent = parse_util.Indent local Cut = parse_util.Cut local ensure = parse_util.ensure - -local function extract_line(str, start_pos) - str = str:sub(start_pos) - local m = str:match"^(.-)\n" - if m then return m end - return str:match"^.-$" -end - -local function mark(name) - return function(...) - return {name, ...} - end -end - -local function insert_pos(pos, value) - if type(value) == "table" then - value[-1] = pos - end - return value -end - -local function pos(patt) - return (lpeg.Cp() * patt) / insert_pos -end - -local function got(what) - return Cmt("", function(str, pos, ...) - local cap = {...} - print("++ got "..what, "["..extract_line(str, pos).."]") - return true - end) -end - -local function flatten_or_mark(name) - return function(tbl) - if #tbl == 1 then return tbl[1] end - table.insert(tbl, 1, name) - return tbl - end -end - --- makes sure the last item in a chain is an index -local _chain_assignable = { index = true, dot = true, slice = true } - -local function is_assignable(node) - if node == "..." then - return false - end - - local t = ntype(node) - return t == "ref" or t == "self" or t == "value" or t == "self_class" or - t == "chain" and _chain_assignable[ntype(node[#node])] or - t == "table" -end - -local function check_assignable(str, pos, value) - if is_assignable(value) then - return true, value - end - return false -end - -local flatten_explist = flatten_or_mark"explist" -local function format_assign(lhs_exps, assign) - if not assign then - return flatten_explist(lhs_exps) - end - - for _, assign_exp in ipairs(lhs_exps) do - if not is_assignable(assign_exp) then - error {assign_exp, "left hand expression is not assignable"} - end - end - - local t = ntype(assign) - if t == "assign" then - return {"assign", lhs_exps, unpack(assign, 2)} - elseif t == "update" then - return {"update", lhs_exps[1], unpack(assign, 2)} - end - - error "unknown assign expression" -end - --- the if statement only takes a single lhs, so we wrap in table to git to --- "assign" tuple format -local function format_single_assign(lhs, assign) - if assign then - return format_assign({lhs}, assign) - end - return lhs -end - -local function sym(chars) - return Space * chars -end - --- Like sym but doesn't accept whitespace in front -local function symx(chars) - return chars -end - -local function simple_string(delim, allow_interpolation) - local inner = P('\\'..delim) + "\\\\" + (1 - P(delim)) - if allow_interpolation then - local inter = symx"#{" * V"Exp" * sym"}" - inner = (C((inner - inter)^1) + inter / mark"interpolate")^0 - else - inner = C(inner^0) - end - - return C(symx(delim)) * - inner * sym(delim) / mark"string" -end - -local function wrap_func_arg(value) - return {"call", {value}} -end - --- DOCME -local function flatten_func(callee, args) - if #args == 0 then return callee end - - args = {"call", args} - if ntype(callee) == "chain" then - -- check for colon stub that needs arguments - if ntype(callee[#callee]) == "colon_stub" then - local stub = callee[#callee] - stub[1] = "colon" - table.insert(stub, args) - else - table.insert(callee, args) - end - - return callee - end - - return {"chain", callee, args} -end - -local function flatten_string_chain(str, chain, args) - if not chain then return str end - return flatten_func({"chain", str, unpack(chain)}, args) -end - --- transforms a statement that has a line decorator -local function wrap_decorator(stm, dec) - if not dec then return stm end - return { "decorated", stm, dec } -end - -local function check_lua_string(str, pos, right, left) - return #left == #right -end - --- :name in table literal -local function self_assign(name, pos) - return {{"key_literal", name}, {"ref", name, [-1] = pos}} -end +local extract_line = parse_util.extract_line +local mark = parse_util.mark +local pos = parse_util.pos +local got = parse_util.got +local flatten_or_mark = parse_util.flatten_or_mark +local is_assignable = parse_util.is_assignable +local check_assignable = parse_util.check_assignable +local format_assign = parse_util.format_assign +local format_single_assign = parse_util.format_single_assign +local sym = parse_util.sym +local symx = parse_util.symx +local simple_string = parse_util.simple_string +local wrap_func_arg = parse_util.wrap_func_arg +local flatten_func = parse_util.flatten_func +local flatten_string_chain = parse_util.flatten_string_chain +local wrap_decorator = parse_util.wrap_decorator +local check_lua_string = parse_util.check_lua_string +local self_assign = parse_util.self_assign local err_msg = "Failed to parse:%s\n [%d] >> %s" diff --git a/moonscript/parse/util.lua b/moonscript/parse/util.lua index 81a4ca9f..6db63f06 100644 --- a/moonscript/parse/util.lua +++ b/moonscript/parse/util.lua @@ -1,8 +1,14 @@ -local P, C, S +local unpack +unpack = require("moonscript.util").unpack +local P, C, S, Cp, Cmt, V do local _obj_0 = require("lpeg") - P, C, S = _obj_0.P, _obj_0.C, _obj_0.S + P, C, S, Cp, Cmt, V = _obj_0.P, _obj_0.C, _obj_0.S, _obj_0.Cp, _obj_0.Cmt, _obj_0.V end +local ntype +ntype = require("moonscript.types").ntype +local Space +Space = require("moonscript.parse.literals").Space local Indent = C(S("\t ") ^ 0) / function(str) do local sum = 0 @@ -24,8 +30,238 @@ local ensure ensure = function(patt, finally) return patt * finally + finally * Cut end +local extract_line +extract_line = function(str, start_pos) + str = str:sub(start_pos) + do + local m = str:match("^(.-)\n") + if m then + return m + end + end + return str:match("^.-$") +end +local mark +mark = function(name) + return function(...) + return { + name, + ... + } + end +end +local pos +pos = function(patt) + return (Cp() * patt) / function(pos, value) + if type(value) == "table" then + value[-1] = pos + end + return value + end +end +local got +got = function(what) + return Cmt("", function(str, pos) + print("++ got " .. tostring(what), "[" .. tostring(extract_line(str, pos)) .. "]") + return true + end) +end +local flatten_or_mark +flatten_or_mark = function(name) + return function(tbl) + if #tbl == 1 then + return tbl[1] + end + table.insert(tbl, 1, name) + return tbl + end +end +local is_assignable +do + local chain_assignable = { + index = true, + dot = true, + slice = true + } + is_assignable = function(node) + if node == "..." then + return false + end + local _exp_0 = ntype(node) + if "ref" == _exp_0 or "self" == _exp_0 or "value" == _exp_0 or "self_class" == _exp_0 or "table" == _exp_0 then + return true + elseif "chain" == _exp_0 then + return chain_assignable[ntype(node[#node])] + else + return false + end + end +end +local check_assignable +check_assignable = function(str, pos, value) + if is_assignable(value) then + return true, value + else + return false + end +end +local format_assign +do + local flatten_explist = flatten_or_mark("explist") + format_assign = function(lhs_exps, assign) + if not (assign) then + return flatten_explist(lhs_exps) + end + for _index_0 = 1, #lhs_exps do + local assign_exp = lhs_exps[_index_0] + if not (is_assignable(assign_exp)) then + error({ + assign_exp, + "left hand expression is not assignable" + }) + end + end + local t = ntype(assign) + local _exp_0 = t + if "assign" == _exp_0 then + return { + "assign", + lhs_exps, + unpack(assign, 2) + } + elseif "update" == _exp_0 then + return { + "update", + lhs_exps[1], + unpack(assign, 2) + } + else + return error("unknown assign expression: " .. tostring(t)) + end + end +end +local format_single_assign +format_single_assign = function(lhs, assign) + if assign then + return format_assign({ + lhs + }, assign) + else + return lhs + end +end +local sym +sym = function(chars) + return Space * chars +end +local symx +symx = function(chars) + return chars +end +local simple_string +simple_string = function(delim, allow_interpolation) + local inner = P("\\" .. tostring(delim)) + "\\\\" + (1 - P(delim)) + if allow_interpolation then + local interp = symx('#{') * V("Exp") * sym('}') + inner = (C((inner - interp) ^ 1) + interp / mark("interpolate")) ^ 0 + else + inner = C(inner ^ 0) + end + return C(symx(delim)) * inner * sym(delim) / mark("string") +end +local wrap_func_arg +wrap_func_arg = function(value) + return { + "call", + { + value + } + } +end +local flatten_func +flatten_func = function(callee, args) + if #args == 0 then + return callee + end + args = { + "call", + args + } + if ntype(callee) == "chain" then + local stub = callee[#callee] + if ntype(stub) == "colon_stub" then + stub[1] = "colon" + table.insert(stub, args) + else + table.insert(callee, args) + end + return callee + end + return { + "chain", + callee, + args + } +end +local flatten_string_chain +flatten_string_chain = function(str, chain, args) + if not (chain) then + return str + end + return flatten_func({ + "chain", + str, + unpack(chain) + }, args) +end +local wrap_decorator +wrap_decorator = function(stm, dec) + if not (dec) then + return stm + end + return { + "decorated", + stm, + dec + } +end +local check_lua_string +check_lua_string = function(str, pos, right, left) + return #left == #right +end +local self_assign +self_assign = function(name, pos) + return { + { + "key_literal", + name + }, + { + "ref", + name, + [-1] = pos + } + } +end return { Indent = Indent, Cut = Cut, - ensure = ensure + ensure = ensure, + extract_line = extract_line, + mark = mark, + pos = pos, + flatten_or_mark = flatten_or_mark, + is_assignable = is_assignable, + check_assignable = check_assignable, + format_assign = format_assign, + format_single_assign = format_single_assign, + sym = sym, + symx = symx, + simple_string = simple_string, + wrap_func_arg = wrap_func_arg, + flatten_func = flatten_func, + flatten_string_chain = flatten_string_chain, + wrap_decorator = wrap_decorator, + check_lua_string = check_lua_string, + self_assign = self_assign } diff --git a/moonscript/parse/util.moon b/moonscript/parse/util.moon index f10dda99..fc680d7f 100644 --- a/moonscript/parse/util.moon +++ b/moonscript/parse/util.moon @@ -1,5 +1,8 @@ -import P, C, S from require "lpeg" +import unpack from require "moonscript.util" +import P, C, S, Cp, Cmt, V from require "lpeg" +import ntype from require "moonscript.types" +import Space from require "moonscript.parse.literals" -- captures an indentation, returns indent depth Indent = C(S"\t "^0) / (str) -> @@ -18,6 +21,147 @@ Cut = P -> false -- ensures finally runs regardless of whether pattern fails or passes ensure = (patt, finally) -> - patt * finally + finally * Cut + patt * finally + finally * Cut -{ :Indent, :Cut, :ensure } +-- take rest of line from pos out of str +extract_line = (str, start_pos) -> + str = str\sub start_pos + if m = str\match "^(.-)\n" + return m + + str\match "^.-$" + +-- used to identify a capture with a label +mark = (name) -> + (...) -> {name, ...} + +-- wraps pattern to capture pos into node +-- pos is the character offset from the buffer where the node was parsed from. +-- Used to generate error messages +pos = (patt) -> + (Cp! * patt) / (pos, value) -> + if type(value) == "table" + value[-1] = pos + value + +-- generates a debug pattern that always succeeds and prints out where we are +-- in the buffer with a label +got = (what) -> + Cmt "", (str, pos) -> + print "++ got #{what}", "[#{extract_line str, pos}]" + true + +-- converts 1 element array to its value, otherwise marks it +flatten_or_mark = (name) -> + (tbl) -> + return tbl[1] if #tbl == 1 + table.insert tbl, 1, name + tbl + +-- determines if node is able to be on left side of assignment +is_assignable = do + chain_assignable = { index: true, dot: true, slice: true } + + (node) -> + return false if node == "..." + switch ntype node + when "ref", "self", "value", "self_class", "table" + true + when "chain" + chain_assignable[ntype node[#node]] + else + false + +check_assignable = (str, pos, value) -> + if is_assignable value + true, value + else + false + +-- joins the two parts of an assign parse into a single node +format_assign = do + flatten_explist = flatten_or_mark "explist" + + (lhs_exps, assign) -> + unless assign + return flatten_explist lhs_exps + + for assign_exp in *lhs_exps + unless is_assignable assign_exp + error {assign_exp, "left hand expression is not assignable"} + + t = ntype assign + switch t + when "assign" + {"assign", lhs_exps, unpack assign, 2} + when "update" + {"update", lhs_exps[1], unpack assign, 2} + else + error "unknown assign expression: #{t}" + +-- helper for if statement, which only has single lhs +format_single_assign = (lhs, assign) -> + if assign + format_assign {lhs}, assign + else + lhs + + +-- a symbol +sym = (chars) -> Space * chars +-- a symbole that doesn't accept whitespace before it +symx = (chars) -> chars + +-- a constructor for quote delimited strings +simple_string = (delim, allow_interpolation) -> + inner = P("\\#{delim}") + "\\\\" + (1 - P delim) + + inner = if allow_interpolation + interp = symx'#{' * V"Exp" * sym'}' + (C((inner - interp)^1) + interp / mark"interpolate")^0 + else + C inner^0 + + C(symx(delim)) * inner * sym(delim) / mark"string" + +-- wraps a single value in format needed to be passed as function arguments +wrap_func_arg = (value) -> {"call", {value}} + +-- flatten out the parsed function node +flatten_func = (callee, args) -> + return callee if #args == 0 + args = {"call", args} + + if ntype(callee) == "chain" + -- check for colon stub needing arguments + stub = callee[#callee] + if ntype(stub) == "colon_stub" + stub[1] = "colon" + table.insert stub, args + else + table.insert callee, args + + return callee + + {"chain", callee, args} + +flatten_string_chain = (str, chain, args) -> + return str unless chain + flatten_func {"chain", str, unpack chain}, args + +-- constructor for decorator node +wrap_decorator = (stm, dec) -> + return stm unless dec + {"decorated", stm, dec} + +check_lua_string = (str, pos, right, left) -> + #left == #right + +-- constructor for :name self assignments in table literals +self_assign = (name, pos) -> + {{"key_literal", name}, {"ref", name, [-1]: pos}} + +{ :Indent, :Cut, :ensure, :extract_line, :mark, :pos, :flatten_or_mark, + :is_assignable, :check_assignable, :format_assign, :format_single_assign, + :sym, :symx, :simple_string, :wrap_func_arg, :flatten_func, + :flatten_string_chain, :wrap_decorator, :check_lua_string, :self_assign } From c8e6528ef7cac17d6e139e248c1bede90625615b Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 28 Feb 2015 16:55:02 -0800 Subject: [PATCH 260/554] convert parser to moonscript --- moonscript/parse.lua | 635 +++++++++++++++--------------------------- moonscript/parse.moon | 355 +++++++++++++++++++++++ 2 files changed, 583 insertions(+), 407 deletions(-) create mode 100644 moonscript/parse.moon diff --git a/moonscript/parse.lua b/moonscript/parse.lua index af5398cb..12f9062e 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -1,414 +1,235 @@ local debug_grammar = false - -local lpeg = require"lpeg" - +local lpeg = require("lpeg") lpeg.setmaxstack(10000) - -local util = require"moonscript.util" -local data = require"moonscript.data" -local types = require"moonscript.types" -local literals = require "moonscript.parse.literals" -local parse_util = require "moonscript.parse.util" - -local ntype = types.ntype -local trim = util.trim - -local wrap_env = require("moonscript.parse.env").wrap_env - -local unpack = util.unpack - -local Stack = data.Stack - -local R, S, V, P = lpeg.R, lpeg.S, lpeg.V, lpeg.P -local C, Ct, Cmt, Cg, Cb, Cc = lpeg.C, lpeg.Ct, lpeg.Cmt, lpeg.Cg, lpeg.Cb, lpeg.Cc - -local White = literals.White -local Break = literals.Break -local Stop = literals.Stop -local Comment = literals.Comment -local Space = literals.Space -local SomeSpace = literals.SomeSpace -local SpaceBreak = literals.SpaceBreak -local EmptyLine = literals.EmptyLine -local AlphaNum = literals.AlphaNum -local _Name = literals.Name -local Num = literals.Num -local Shebang = literals.Shebang - -local Name = Space * _Name -Num = Space * (Num / function(value) return {"number", value} end) - -local Indent = parse_util.Indent -local Cut = parse_util.Cut -local ensure = parse_util.ensure -local extract_line = parse_util.extract_line -local mark = parse_util.mark -local pos = parse_util.pos -local got = parse_util.got -local flatten_or_mark = parse_util.flatten_or_mark -local is_assignable = parse_util.is_assignable -local check_assignable = parse_util.check_assignable -local format_assign = parse_util.format_assign -local format_single_assign = parse_util.format_single_assign -local sym = parse_util.sym -local symx = parse_util.symx -local simple_string = parse_util.simple_string -local wrap_func_arg = parse_util.wrap_func_arg -local flatten_func = parse_util.flatten_func -local flatten_string_chain = parse_util.flatten_string_chain -local wrap_decorator = parse_util.wrap_decorator -local check_lua_string = parse_util.check_lua_string -local self_assign = parse_util.self_assign - local err_msg = "Failed to parse:%s\n [%d] >> %s" - +local Stack +Stack = require("moonscript.data").Stack +local trim, pos_to_line, get_line +do + local _obj_0 = require("moonscript.util") + trim, pos_to_line, get_line = _obj_0.trim, _obj_0.pos_to_line, _obj_0.get_line +end +local unpack +unpack = require("moonscript.util").unpack +local wrap_env +wrap_env = require("moonscript.parse.env").wrap_env +local R, S, V, P, C, Ct, Cmt, Cg, Cb, Cc +R, S, V, P, C, Ct, Cmt, Cg, Cb, Cc = lpeg.R, lpeg.S, lpeg.V, lpeg.P, lpeg.C, lpeg.Ct, lpeg.Cmt, lpeg.Cg, lpeg.Cb, lpeg.Cc +local White, Break, Stop, Comment, Space, SomeSpace, SpaceBreak, EmptyLine, AlphaNum, Num, Shebang, _Name +do + local _obj_0 = require("moonscript.parse.literals") + White, Break, Stop, Comment, Space, SomeSpace, SpaceBreak, EmptyLine, AlphaNum, Num, Shebang, _Name = _obj_0.White, _obj_0.Break, _obj_0.Stop, _obj_0.Comment, _obj_0.Space, _obj_0.SomeSpace, _obj_0.SpaceBreak, _obj_0.EmptyLine, _obj_0.AlphaNum, _obj_0.Num, _obj_0.Shebang, _obj_0.Name +end +local SpaceName = Space * _Name +Num = Space * (Num / function(v) + return { + "number", + v + } +end) +local Indent, Cut, ensure, extract_line, mark, pos, flatten_or_mark, is_assignable, check_assignable, format_assign, format_single_assign, sym, symx, simple_string, wrap_func_arg, flatten_func, flatten_string_chain, wrap_decorator, check_lua_string, self_assign +do + local _obj_0 = require("moonscript.parse.util") + Indent, Cut, ensure, extract_line, mark, pos, flatten_or_mark, is_assignable, check_assignable, format_assign, format_single_assign, sym, symx, simple_string, wrap_func_arg, flatten_func, flatten_string_chain, wrap_decorator, check_lua_string, self_assign = _obj_0.Indent, _obj_0.Cut, _obj_0.ensure, _obj_0.extract_line, _obj_0.mark, _obj_0.pos, _obj_0.flatten_or_mark, _obj_0.is_assignable, _obj_0.check_assignable, _obj_0.format_assign, _obj_0.format_single_assign, _obj_0.sym, _obj_0.symx, _obj_0.simple_string, _obj_0.wrap_func_arg, _obj_0.flatten_func, _obj_0.flatten_string_chain, _obj_0.wrap_decorator, _obj_0.check_lua_string, _obj_0.self_assign +end local build_grammar = wrap_env(debug_grammar, function() - local _indent = Stack(0) -- current indent - local _do_stack = Stack(0) - - local last_pos = 0 -- used to know where to report error - local function check_indent(str, pos, indent) - last_pos = pos - return _indent:top() == indent - end - - local function advance_indent(str, pos, indent) - local top = _indent:top() - if top ~= -1 and indent > _indent:top() then - _indent:push(indent) - return true - end - end - - local function push_indent(str, pos, indent) - _indent:push(indent) - return true - end - - local function pop_indent(str, pos) - if not _indent:pop() then error("unexpected outdent") end - return true - end - - - local function check_do(str, pos, do_node) - local top = _do_stack:top() - if top == nil or top then - return true, do_node - end - return false - end - - local function disable_do(str_pos) - _do_stack:push(false) - return true - end - - local function pop_do(str, pos) - if nil == _do_stack:pop() then error("unexpected do pop") end - return true - end - - local DisableDo = Cmt("", disable_do) - local PopDo = Cmt("", pop_do) - - local keywords = {} - local function key(chars) - keywords[chars] = true - return Space * chars * -AlphaNum - end - - local function op(word) - local patt = Space * C(word) - if word:match("^%w*$") then - keywords[word] = true - patt = patt * -AlphaNum - end - return patt - end - - -- make sure name is not a keyword - local Name = Cmt(Name, function(str, pos, name) - if keywords[name] then return false end - return true - end) / trim - - local SelfName = Space * "@" * ( - "@" * (_Name / mark"self_class" + Cc"self.__class") + - _Name / mark"self" + Cc"self") - - local KeyName = SelfName + Space * _Name / mark"key_literal" - local VarArg = Space * P"..." / trim - - local g = lpeg.P{ - File, - File = Shebang^-1 * (Block + Ct""), - Block = Ct(Line * (Break^1 * Line)^0), - CheckIndent = Cmt(Indent, check_indent), -- validates line is in correct indent - Line = (CheckIndent * Statement + Space * #Stop), - - Statement = pos( - Import + While + With + For + ForEach + Switch + Return + - Local + Export + BreakLoop + - Ct(ExpList) * (Update + Assign)^-1 / format_assign - ) * Space * (( - -- statement decorators - key"if" * Exp * (key"else" * Exp)^-1 * Space / mark"if" + - key"unless" * Exp / mark"unless" + - CompInner / mark"comprehension" - ) * Space)^-1 / wrap_decorator, - - Body = Space^-1 * Break * EmptyLine^0 * InBlock + Ct(Statement), -- either a statement, or an indented block - - Advance = #Cmt(Indent, advance_indent), -- Advances the indent, gives back whitespace for CheckIndent - PushIndent = Cmt(Indent, push_indent), - PreventIndent = Cmt(Cc(-1), push_indent), - PopIndent = Cmt("", pop_indent), - InBlock = Advance * Block * PopIndent, - - Local = key"local" * ((op"*" + op"^") / mark"declare_glob" + Ct(NameList) / mark"declare_with_shadows"), - - Import = key"import" * Ct(ImportNameList) * SpaceBreak^0 * key"from" * Exp / mark"import", - ImportName = (sym"\\" * Ct(Cc"colon_stub" * Name) + Name), - ImportNameList = SpaceBreak^0 * ImportName * ((SpaceBreak^1 + sym"," * SpaceBreak^0) * ImportName)^0, - - BreakLoop = Ct(key"break"/trim) + Ct(key"continue"/trim), - - Return = key"return" * (ExpListLow/mark"explist" + C"") / mark"return", - - WithExp = Ct(ExpList) * Assign^-1 / format_assign, - With = key"with" * DisableDo * ensure(WithExp, PopDo) * key"do"^-1 * Body / mark"with", - - Switch = key"switch" * DisableDo * ensure(Exp, PopDo) * key"do"^-1 * Space^-1 * Break * SwitchBlock / mark"switch", - - SwitchBlock = EmptyLine^0 * Advance * Ct(SwitchCase * (Break^1 * SwitchCase)^0 * (Break^1 * SwitchElse)^-1) * PopIndent, - SwitchCase = key"when" * Ct(ExpList) * key"then"^-1 * Body / mark"case", - SwitchElse = key"else" * Body / mark"else", - - IfCond = Exp * Assign^-1 / format_single_assign, - - If = key"if" * IfCond * key"then"^-1 * Body * - ((Break * CheckIndent)^-1 * EmptyLine^0 * key"elseif" * pos(IfCond) * key"then"^-1 * Body / mark"elseif")^0 * - ((Break * CheckIndent)^-1 * EmptyLine^0 * key"else" * Body / mark"else")^-1 / mark"if", - - Unless = key"unless" * IfCond * key"then"^-1 * Body * - ((Break * CheckIndent)^-1 * EmptyLine^0 * key"else" * Body / mark"else")^-1 / mark"unless", - - While = key"while" * DisableDo * ensure(Exp, PopDo) * key"do"^-1 * Body / mark"while", - - For = key"for" * DisableDo * ensure(Name * sym"=" * Ct(Exp * sym"," * Exp * (sym"," * Exp)^-1), PopDo) * - key"do"^-1 * Body / mark"for", - - ForEach = key"for" * Ct(AssignableNameList) * key"in" * DisableDo * ensure(Ct(sym"*" * Exp / mark"unpack" + ExpList), PopDo) * key"do"^-1 * Body / mark"foreach", - - Do = key"do" * Body / mark"do", - - Comprehension = sym"[" * Exp * CompInner * sym"]" / mark"comprehension", - - TblComprehension = sym"{" * Ct(Exp * (sym"," * Exp)^-1) * CompInner * sym"}" / mark"tblcomprehension", - - 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", - - CharOperators = Space * C(S"+-*/%^><"), - WordOperators = op"or" + op"and" + op"<=" + op">=" + op"~=" + op"!=" + op"==" + op"..", - BinaryOperator = (WordOperators + CharOperators) * SpaceBreak^0, - - Assignable = Cmt(DotChain + Chain, check_assignable) + Name + SelfName, - Exp = Ct(Value * (BinaryOperator * Value)^0) / flatten_or_mark"exp", - - SimpleValue = - If + Unless + - Switch + - With + - ClassDecl + - ForEach + For + While + - Cmt(Do, check_do) + - sym"-" * -SomeSpace * Exp / mark"minus" + - sym"#" * Exp / mark"length" + - key"not" * Exp / mark"not" + - TblComprehension + - TableLit + - Comprehension + - FunLit + - Num, - - ChainValue = -- a function call or an object access - StringChain + - ((Chain + DotChain + Callable) * Ct(InvokeArgs^-1)) / flatten_func, - - Value = pos( - SimpleValue + - Ct(KeyValueList) / mark"table" + - ChainValue), - - SliceValue = SimpleValue + ChainValue, - - StringChain = String * - (Ct((ColonCall + ColonSuffix) * ChainTail^-1) * Ct(InvokeArgs^-1))^-1 / flatten_string_chain, - - String = Space * DoubleString + Space * SingleString + LuaString, - SingleString = simple_string("'"), - DoubleString = simple_string('"', true), - - LuaString = Cg(LuaStringOpen, "string_open") * Cb"string_open" * Break^-1 * - C((1 - Cmt(C(LuaStringClose) * Cb"string_open", check_lua_string))^0) * - LuaStringClose / mark"string", - - LuaStringOpen = sym"[" * P"="^0 * "[" / trim, - LuaStringClose = "]" * P"="^0 * "]", - - Callable = pos(Name / mark"ref") + SelfName + VarArg + Parens / mark"parens", - Parens = sym"(" * SpaceBreak^0 * Exp * SpaceBreak^0 * sym")", - - FnArgs = symx"(" * SpaceBreak^0 * Ct(ExpList^-1) * SpaceBreak^0 * sym")" + sym"!" * -P"=" * Ct"", - - ChainTail = ChainItem^1 * ColonSuffix^-1 + ColonSuffix, - - -- a list of funcalls and indexes on a callable - Chain = Callable * ChainTail / mark"chain", - - -- shorthand dot call for use in with statement - DotChain = - (sym"." * Cc(-1) * (_Name / mark"dot") * ChainTail^-1) / mark"chain" + - (sym"\\" * Cc(-1) * ( - (_Name * Invoke / mark"colon") * ChainTail^-1 + - (_Name / mark"colon_stub") - )) / mark"chain", - - ChainItem = - Invoke + - Slice + - symx"[" * Exp/mark"index" * sym"]" + - symx"." * _Name/mark"dot" + - ColonCall, - - Slice = symx"[" * (SliceValue + Cc(1)) * sym"," * (SliceValue + Cc"") * - (sym"," * SliceValue)^-1 *sym"]" / mark"slice", - - ColonCall = symx"\\" * (_Name * Invoke) / mark"colon", - ColonSuffix = symx"\\" * _Name / mark"colon_stub", - - Invoke = FnArgs/mark"call" + - SingleString / wrap_func_arg + - DoubleString / wrap_func_arg, - - TableValue = KeyValue + Ct(Exp), - - TableLit = sym"{" * Ct( - TableValueList^-1 * sym","^-1 * - (SpaceBreak * TableLitLine * (sym","^-1 * SpaceBreak * TableLitLine)^0 * sym","^-1)^-1 - ) * White * sym"}" / mark"table", - - TableValueList = TableValue * (sym"," * TableValue)^0, - TableLitLine = PushIndent * ((TableValueList * PopIndent) + (PopIndent * Cut)) + Space, - - -- the unbounded table - TableBlockInner = Ct(KeyValueLine * (SpaceBreak^1 * KeyValueLine)^0), - TableBlock = SpaceBreak^1 * Advance * ensure(TableBlockInner, PopIndent) / mark"table", - - ClassDecl = key"class" * -P":" * (Assignable + Cc(nil)) * (key"extends" * PreventIndent * ensure(Exp, PopIndent) + C"")^-1 * (ClassBlock + Ct("")) / mark"class", - - ClassBlock = SpaceBreak^1 * Advance * - Ct(ClassLine * (SpaceBreak^1 * ClassLine)^0) * PopIndent, - ClassLine = CheckIndent * (( - KeyValueList / mark"props" + - Statement / mark"stm" + - Exp / mark"stm" - ) * sym","^-1), - - Export = key"export" * ( - Cc"class" * ClassDecl + - op"*" + op"^" + - Ct(NameList) * (sym"=" * Ct(ExpListLow))^-1) / mark"export", - - KeyValue = (sym":" * -SomeSpace * Name * lpeg.Cp()) / self_assign + Ct((KeyName + sym"[" * Exp * sym"]" + DoubleString + SingleString) * symx":" * (Exp + TableBlock + SpaceBreak^1 * Exp)), - KeyValueList = KeyValue * (sym"," * KeyValue)^0, - KeyValueLine = CheckIndent * KeyValueList * sym","^-1, - - FnArgsDef = sym"(" * Ct(FnArgDefList^-1) * - (key"using" * Ct(NameList + Space * "nil") + Ct"") * - sym")" + Ct"" * Ct"", - - FnArgDefList = FnArgDef * (sym"," * FnArgDef)^0 * (sym"," * Ct(VarArg))^0 + Ct(VarArg), - FnArgDef = Ct((Name + SelfName) * (sym"=" * Exp)^-1), - - FunLit = FnArgsDef * - (sym"->" * Cc"slim" + sym"=>" * Cc"fat") * - (Body + Ct"") / mark"fndef", - - NameList = Name * (sym"," * Name)^0, - NameOrDestructure = Name + TableLit, - AssignableNameList = NameOrDestructure * (sym"," * NameOrDestructure)^0, - - ExpList = Exp * (sym"," * Exp)^0, - ExpListLow = Exp * ((sym"," + sym";") * Exp)^0, - - InvokeArgs = -P"-" * (ExpList * (sym"," * (TableBlock + SpaceBreak * Advance * ArgBlock * TableBlock^-1) + TableBlock)^-1 + TableBlock), - ArgBlock = ArgLine * (sym"," * SpaceBreak * ArgLine)^0 * PopIndent, - ArgLine = CheckIndent * ExpList - } - - return { - _g = White * g * White * -1, - match = function(self, str, ...) - - local pos_to_line = function(pos) - return util.pos_to_line(str, pos) - end - - local get_line = function(num) - return util.get_line(str, num) - end - - local tree - local parse_args = {...} - - local pass, err = xpcall(function() - tree = self._g:match(str, unpack(parse_args)) - end, function(err) - return debug.traceback(err, 2) - end) - - -- regular error, let it bubble up - if type(err) == "string" then - return nil, err - end - - if not tree then - local pos = last_pos - local msg - - if err then - local node - node, msg = unpack(err) - msg = msg and " " .. msg - pos = node[-1] - end - - local line_no = pos_to_line(pos) - local line_str = get_line(line_no) or "" - - return nil, err_msg:format(msg or "", line_no, trim(line_str)) - end - return tree - end - } + local _indent = Stack(0) + local _do_stack = Stack(0) + local last_pos = 0 + local check_indent + check_indent = function(str, pos, indent) + last_pos = pos + return _indent:top() == indent + end + local advance_indent + advance_indent = function(str, pos, indent) + local top = _indent:top() + if top ~= -1 and indent > top then + _indent:push(indent) + return true + end + end + local push_indent + push_indent = function(str, pos, indent) + _indent:push(indent) + return true + end + local pop_indent + pop_indent = function() + assert(_indent:pop(), "unexpected outdent") + return true + end + local check_do + check_do = function(str, pos, do_node) + local top = _do_stack:top() + if top == nil or top then + return true, do_node + end + return false + end + local disable_do + disable_do = function() + _do_stack:push(false) + return true + end + local pop_do + pop_do = function() + assert(_do_stack:pop() ~= nil, "unexpected do pop") + return true + end + local DisableDo = Cmt("", disable_do) + local PopDo = Cmt("", pop_do) + local keywords = { } + local key + key = function(chars) + keywords[chars] = true + return Space * chars * -AlphaNum + end + local op + op = function(chars) + local patt = Space * C(chars) + if chars:match("^%w*$") then + keywords[chars] = true + patt = patt * -AlphaNum + end + return patt + end + local Name = Cmt(SpaceName, function(str, pos, name) + if keywords[name] then + return false + end + return true + end) / trim + local SelfName = Space * "@" * ("@" * (_Name / mark("self_class") + Cc("self.__class")) + _Name / mark("self") + Cc("self")) + local KeyName = SelfName + Space * _Name / mark("key_literal") + local VarArg = Space * P("...") / trim + local g = P({ + File, + File = Shebang ^ -1 * (Block + Ct("")), + Block = Ct(Line * (Break ^ 1 * Line) ^ 0), + CheckIndent = Cmt(Indent, check_indent), + Line = (CheckIndent * Statement + Space * #Stop), + Statement = pos(Import + While + With + For + ForEach + Switch + Return + Local + Export + BreakLoop + Ct(ExpList) * (Update + Assign) ^ -1 / format_assign) * Space * ((key("if") * Exp * (key("else") * Exp) ^ -1 * Space / mark("if") + key("unless") * Exp / mark("unless") + CompInner / mark("comprehension")) * Space) ^ -1 / wrap_decorator, + Body = Space ^ -1 * Break * EmptyLine ^ 0 * InBlock + Ct(Statement), + Advance = #Cmt(Indent, advance_indent), + PushIndent = Cmt(Indent, push_indent), + PreventIndent = Cmt(Cc(-1), push_indent), + PopIndent = Cmt("", pop_indent), + InBlock = Advance * Block * PopIndent, + Local = key("local") * ((op("*") + op("^")) / mark("declare_glob") + Ct(NameList) / mark("declare_with_shadows")), + Import = key("import") * Ct(ImportNameList) * SpaceBreak ^ 0 * key("from") * Exp / mark("import"), + ImportName = (sym("\\") * Ct(Cc("colon_stub") * Name) + Name), + ImportNameList = SpaceBreak ^ 0 * ImportName * ((SpaceBreak ^ 1 + sym(",") * SpaceBreak ^ 0) * ImportName) ^ 0, + BreakLoop = Ct(key("break") / trim) + Ct(key("continue") / trim), + Return = key("return") * (ExpListLow / mark("explist") + C("")) / mark("return"), + WithExp = Ct(ExpList) * Assign ^ -1 / format_assign, + With = key("with") * DisableDo * ensure(WithExp, PopDo) * key("do") ^ -1 * Body / mark("with"), + Switch = key("switch") * DisableDo * ensure(Exp, PopDo) * key("do") ^ -1 * Space ^ -1 * Break * SwitchBlock / mark("switch"), + SwitchBlock = EmptyLine ^ 0 * Advance * Ct(SwitchCase * (Break ^ 1 * SwitchCase) ^ 0 * (Break ^ 1 * SwitchElse) ^ -1) * PopIndent, + SwitchCase = key("when") * Ct(ExpList) * key("then") ^ -1 * Body / mark("case"), + SwitchElse = key("else") * Body / mark("else"), + IfCond = Exp * Assign ^ -1 / format_single_assign, + If = key("if") * IfCond * key("then") ^ -1 * Body * ((Break * CheckIndent) ^ -1 * EmptyLine ^ 0 * key("elseif") * pos(IfCond) * key("then") ^ -1 * Body / mark("elseif")) ^ 0 * ((Break * CheckIndent) ^ -1 * EmptyLine ^ 0 * key("else") * Body / mark("else")) ^ -1 / mark("if"), + Unless = key("unless") * IfCond * key("then") ^ -1 * Body * ((Break * CheckIndent) ^ -1 * EmptyLine ^ 0 * key("else") * Body / mark("else")) ^ -1 / mark("unless"), + While = key("while") * DisableDo * ensure(Exp, PopDo) * key("do") ^ -1 * Body / mark("while"), + For = key("for") * DisableDo * ensure(Name * sym("=") * Ct(Exp * sym(",") * Exp * (sym(",") * Exp) ^ -1), PopDo) * key("do") ^ -1 * Body / mark("for"), + ForEach = key("for") * Ct(AssignableNameList) * key("in") * DisableDo * ensure(Ct(sym("*") * Exp / mark("unpack") + ExpList), PopDo) * key("do") ^ -1 * Body / mark("foreach"), + Do = key("do") * Body / mark("do"), + Comprehension = sym("[") * Exp * CompInner * sym("]") / mark("comprehension"), + TblComprehension = sym("{") * Ct(Exp * (sym(",") * Exp) ^ -1) * CompInner * sym("}") / mark("tblcomprehension"), + 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"), + CharOperators = Space * C(S("+-*/%^><")), + WordOperators = op("or") + op("and") + op("<=") + op(">=") + op("~=") + op("!=") + op("==") + op(".."), + BinaryOperator = (WordOperators + CharOperators) * SpaceBreak ^ 0, + Assignable = Cmt(DotChain + Chain, check_assignable) + Name + SelfName, + Exp = Ct(Value * (BinaryOperator * Value) ^ 0) / flatten_or_mark("exp"), + SimpleValue = If + Unless + Switch + With + ClassDecl + ForEach + For + While + Cmt(Do, check_do) + sym("-") * -SomeSpace * Exp / mark("minus") + sym("#") * Exp / mark("length") + key("not") * Exp / mark("not") + TblComprehension + TableLit + Comprehension + FunLit + Num, + ChainValue = StringChain + ((Chain + DotChain + Callable) * Ct(InvokeArgs ^ -1)) / flatten_func, + Value = pos(SimpleValue + Ct(KeyValueList) / mark("table") + ChainValue), + SliceValue = SimpleValue + ChainValue, + StringChain = String * (Ct((ColonCall + ColonSuffix) * ChainTail ^ -1) * Ct(InvokeArgs ^ -1)) ^ -1 / flatten_string_chain, + String = Space * DoubleString + Space * SingleString + LuaString, + SingleString = simple_string("'"), + DoubleString = simple_string('"', true), + LuaString = Cg(LuaStringOpen, "string_open") * Cb("string_open") * Break ^ -1 * C((1 - Cmt(C(LuaStringClose) * Cb("string_open"), check_lua_string)) ^ 0) * LuaStringClose / mark("string"), + LuaStringOpen = sym("[") * P("=") ^ 0 * "[" / trim, + LuaStringClose = "]" * P("=") ^ 0 * "]", + Callable = pos(Name / mark("ref")) + SelfName + VarArg + Parens / mark("parens"), + Parens = sym("(") * SpaceBreak ^ 0 * Exp * SpaceBreak ^ 0 * sym(")"), + FnArgs = symx("(") * SpaceBreak ^ 0 * Ct(ExpList ^ -1) * SpaceBreak ^ 0 * sym(")") + sym("!") * -P("=") * Ct(""), + ChainTail = ChainItem ^ 1 * ColonSuffix ^ -1 + ColonSuffix, + Chain = Callable * ChainTail / mark("chain"), + DotChain = (sym(".") * Cc(-1) * (_Name / mark("dot")) * ChainTail ^ -1) / mark("chain") + (sym("\\") * Cc(-1) * ((_Name * Invoke / mark("colon")) * ChainTail ^ -1 + (_Name / mark("colon_stub")))) / mark("chain"), + ChainItem = Invoke + Slice + symx("[") * Exp / mark("index") * sym("]") + symx(".") * _Name / mark("dot") + ColonCall, + Slice = symx("[") * (SliceValue + Cc(1)) * sym(",") * (SliceValue + Cc("")) * (sym(",") * SliceValue) ^ -1 * sym("]") / mark("slice"), + ColonCall = symx("\\") * (_Name * Invoke) / mark("colon"), + ColonSuffix = symx("\\") * _Name / mark("colon_stub"), + Invoke = FnArgs / mark("call") + SingleString / wrap_func_arg + DoubleString / wrap_func_arg, + TableValue = KeyValue + Ct(Exp), + TableLit = sym("{") * Ct(TableValueList ^ -1 * sym(",") ^ -1 * (SpaceBreak * TableLitLine * (sym(",") ^ -1 * SpaceBreak * TableLitLine) ^ 0 * sym(",") ^ -1) ^ -1) * White * sym("}") / mark("table"), + TableValueList = TableValue * (sym(",") * TableValue) ^ 0, + TableLitLine = PushIndent * ((TableValueList * PopIndent) + (PopIndent * Cut)) + Space, + TableBlockInner = Ct(KeyValueLine * (SpaceBreak ^ 1 * KeyValueLine) ^ 0), + TableBlock = SpaceBreak ^ 1 * Advance * ensure(TableBlockInner, PopIndent) / mark("table"), + ClassDecl = key("class") * -P(":") * (Assignable + Cc(nil)) * (key("extends") * PreventIndent * ensure(Exp, PopIndent) + C("")) ^ -1 * (ClassBlock + Ct("")) / mark("class"), + ClassBlock = SpaceBreak ^ 1 * Advance * Ct(ClassLine * (SpaceBreak ^ 1 * ClassLine) ^ 0) * PopIndent, + ClassLine = CheckIndent * ((KeyValueList / mark("props") + Statement / mark("stm") + Exp / mark("stm")) * sym(",") ^ -1), + Export = key("export") * (Cc("class") * ClassDecl + op("*") + op("^") + Ct(NameList) * (sym("=") * Ct(ExpListLow)) ^ -1) / mark("export"), + KeyValue = (sym(":") * -SomeSpace * Name * lpeg.Cp()) / self_assign + Ct((KeyName + sym("[") * Exp * sym("]") + DoubleString + SingleString) * symx(":") * (Exp + TableBlock + SpaceBreak ^ 1 * Exp)), + KeyValueList = KeyValue * (sym(",") * KeyValue) ^ 0, + KeyValueLine = CheckIndent * KeyValueList * sym(",") ^ -1, + FnArgsDef = sym("(") * Ct(FnArgDefList ^ -1) * (key("using") * Ct(NameList + Space * "nil") + Ct("")) * sym(")") + Ct("") * Ct(""), + FnArgDefList = FnArgDef * (sym(",") * FnArgDef) ^ 0 * (sym(",") * Ct(VarArg)) ^ 0 + Ct(VarArg), + FnArgDef = Ct((Name + SelfName) * (sym("=") * Exp) ^ -1), + FunLit = FnArgsDef * (sym("->") * Cc("slim") + sym("=>") * Cc("fat")) * (Body + Ct("")) / mark("fndef"), + NameList = Name * (sym(",") * Name) ^ 0, + NameOrDestructure = Name + TableLit, + AssignableNameList = NameOrDestructure * (sym(",") * NameOrDestructure) ^ 0, + ExpList = Exp * (sym(",") * Exp) ^ 0, + ExpListLow = Exp * ((sym(",") + sym(";")) * Exp) ^ 0, + InvokeArgs = -P("-") * (ExpList * (sym(",") * (TableBlock + SpaceBreak * Advance * ArgBlock * TableBlock ^ -1) + TableBlock) ^ -1 + TableBlock), + ArgBlock = ArgLine * (sym(",") * SpaceBreak * ArgLine) ^ 0 * PopIndent, + ArgLine = CheckIndent * ExpList + }) + local file_grammar = White * g * White * -1 + return { + match = function(self, str) + local tree + local _, err = xpcall((function() + tree = file_grammar:match(str) + end), function(err) + return debug.traceback(err, 2) + end) + if type(err) == "string" then + return nil, err + end + if not (tree) then + local msg + pos = last_pos + if err then + local node + node, msg = unpack(err) + if msg then + msg = " " .. msg + end + pos = node[-1] + end + local line_no = pos_to_line(str, pos) + local line_str = get_line(str, line_no) or "" + return nil, err_msg:format(msg or "", line_no, trim(line_str)) + end + return tree + end + } end) - return { - extract_line = extract_line, - - -- parse a string - -- returns tree, or nil and error message - string = function (str) - local g = build_grammar() - return g:match(str) - end + extract_line = extract_line, + string = function(str) + return build_grammar():match(str) + end } - diff --git a/moonscript/parse.moon b/moonscript/parse.moon new file mode 100644 index 00000000..a58d9cb2 --- /dev/null +++ b/moonscript/parse.moon @@ -0,0 +1,355 @@ +debug_grammar = false +lpeg = require "lpeg" + +lpeg.setmaxstack 10000 -- whoa + +err_msg = "Failed to parse:%s\n [%d] >> %s" + +import Stack from require "moonscript.data" +import trim, pos_to_line, get_line from require"moonscript.util" +import unpack from require "moonscript.util" +import wrap_env from require "moonscript.parse.env" + +{ + :R, :S, :V, :P, :C, :Ct, :Cmt, :Cg, :Cb, :Cc +} = lpeg + +{ + :White, :Break, :Stop, :Comment, :Space, :SomeSpace, :SpaceBreak, :EmptyLine, + :AlphaNum, :Num, :Shebang + Name: _Name +} = require "moonscript.parse.literals" + + +SpaceName = Space * _Name +Num = Space * (Num / (v) -> {"number", v}) + +{ + :Indent, :Cut, :ensure, :extract_line, :mark, :pos, :flatten_or_mark, + :is_assignable, :check_assignable, :format_assign, :format_single_assign, + :sym, :symx, :simple_string, :wrap_func_arg, :flatten_func, + :flatten_string_chain, :wrap_decorator, :check_lua_string, :self_assign +} = require "moonscript.parse.util" + + +build_grammar = wrap_env debug_grammar, -> + _indent = Stack 0 + _do_stack = Stack 0 + + last_pos = 0 -- last pos we saw, used to report error location + + check_indent = (str, pos, indent) -> + last_pos = pos + _indent\top! == indent + + advance_indent = (str, pos, indent) -> + top = _indent\top! + if top != -1 and indent > top + _indent\push indent + true + + push_indent = (str, pos, indent) -> + _indent\push indent + true + + pop_indent = -> + assert _indent\pop!, "unexpected outdent" + true + + check_do = (str, pos, do_node) -> + top = _do_stack\top! + if top == nil or top + return true, do_node + false + + disable_do = -> + _do_stack\push false + true + + pop_do = -> + assert _do_stack\pop! != nil, "unexpected do pop" + true + + DisableDo = Cmt "", disable_do + PopDo = Cmt "", pop_do + + keywords = {} + key = (chars) -> + keywords[chars] = true + Space * chars * -AlphaNum + + op = (chars) -> + patt = Space * C chars + -- it's a word, treat like keyword + if chars\match "^%w*$" + keywords[chars] = true + patt *= -AlphaNum + + patt + + Name = Cmt(SpaceName, (str, pos, name) -> + return false if keywords[name] + true + ) / trim + + SelfName = Space * "@" * ( + "@" * (_Name / mark"self_class" + Cc"self.__class") + + _Name / mark"self" + + Cc"self" -- @ by itself + ) + + KeyName = SelfName + Space * _Name / mark"key_literal" + VarArg = Space * P"..." / trim + + g = P { + File + File: Shebang^-1 * (Block + Ct"") + Block: Ct(Line * (Break^1 * Line)^0) + CheckIndent: Cmt(Indent, check_indent), -- validates line is in correct indent + Line: (CheckIndent * Statement + Space * #Stop) + + Statement: pos( + Import + While + With + For + ForEach + Switch + Return + + Local + Export + BreakLoop + + Ct(ExpList) * (Update + Assign)^-1 / format_assign + ) * Space * (( + -- statement decorators + key"if" * Exp * (key"else" * Exp)^-1 * Space / mark"if" + + key"unless" * Exp / mark"unless" + + CompInner / mark"comprehension" + ) * Space)^-1 / wrap_decorator + + Body: Space^-1 * Break * EmptyLine^0 * InBlock + Ct(Statement), -- either a statement, or an indented block + + Advance: #Cmt(Indent, advance_indent), -- Advances the indent, gives back whitespace for CheckIndent + PushIndent: Cmt(Indent, push_indent) + PreventIndent: Cmt(Cc(-1), push_indent) + PopIndent: Cmt("", pop_indent) + InBlock: Advance * Block * PopIndent + + Local: key"local" * ((op"*" + op"^") / mark"declare_glob" + Ct(NameList) / mark"declare_with_shadows") + + Import: key"import" * Ct(ImportNameList) * SpaceBreak^0 * key"from" * Exp / mark"import" + ImportName: (sym"\\" * Ct(Cc"colon_stub" * Name) + Name) + ImportNameList: SpaceBreak^0 * ImportName * ((SpaceBreak^1 + sym"," * SpaceBreak^0) * ImportName)^0 + + BreakLoop: Ct(key"break"/trim) + Ct(key"continue"/trim) + + Return: key"return" * (ExpListLow/mark"explist" + C"") / mark"return" + + WithExp: Ct(ExpList) * Assign^-1 / format_assign + With: key"with" * DisableDo * ensure(WithExp, PopDo) * key"do"^-1 * Body / mark"with" + + Switch: key"switch" * DisableDo * ensure(Exp, PopDo) * key"do"^-1 * Space^-1 * Break * SwitchBlock / mark"switch" + + SwitchBlock: EmptyLine^0 * Advance * Ct(SwitchCase * (Break^1 * SwitchCase)^0 * (Break^1 * SwitchElse)^-1) * PopIndent + SwitchCase: key"when" * Ct(ExpList) * key"then"^-1 * Body / mark"case" + SwitchElse: key"else" * Body / mark"else" + + IfCond: Exp * Assign^-1 / format_single_assign + + If: key"if" * IfCond * key"then"^-1 * Body * + ((Break * CheckIndent)^-1 * EmptyLine^0 * key"elseif" * pos(IfCond) * key"then"^-1 * Body / mark"elseif")^0 * + ((Break * CheckIndent)^-1 * EmptyLine^0 * key"else" * Body / mark"else")^-1 / mark"if" + + Unless: key"unless" * IfCond * key"then"^-1 * Body * + ((Break * CheckIndent)^-1 * EmptyLine^0 * key"else" * Body / mark"else")^-1 / mark"unless" + + While: key"while" * DisableDo * ensure(Exp, PopDo) * key"do"^-1 * Body / mark"while" + + For: key"for" * DisableDo * ensure(Name * sym"=" * Ct(Exp * sym"," * Exp * (sym"," * Exp)^-1), PopDo) * + key"do"^-1 * Body / mark"for" + + ForEach: key"for" * Ct(AssignableNameList) * key"in" * DisableDo * ensure(Ct(sym"*" * Exp / mark"unpack" + ExpList), PopDo) * key"do"^-1 * Body / mark"foreach" + + Do: key"do" * Body / mark"do" + + Comprehension: sym"[" * Exp * CompInner * sym"]" / mark"comprehension" + + TblComprehension: sym"{" * Ct(Exp * (sym"," * Exp)^-1) * CompInner * sym"}" / mark"tblcomprehension" + + 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" + + CharOperators: Space * C(S"+-*/%^><") + WordOperators: op"or" + op"and" + op"<=" + op">=" + op"~=" + op"!=" + op"==" + op".." + BinaryOperator: (WordOperators + CharOperators) * SpaceBreak^0 + + Assignable: Cmt(DotChain + Chain, check_assignable) + Name + SelfName + Exp: Ct(Value * (BinaryOperator * Value)^0) / flatten_or_mark"exp" + + SimpleValue: + If + Unless + + Switch + + With + + ClassDecl + + ForEach + For + While + + Cmt(Do, check_do) + + sym"-" * -SomeSpace * Exp / mark"minus" + + sym"#" * Exp / mark"length" + + key"not" * Exp / mark"not" + + TblComprehension + + TableLit + + Comprehension + + FunLit + + Num + + ChainValue: -- a function call or an object access + StringChain + + ((Chain + DotChain + Callable) * Ct(InvokeArgs^-1)) / flatten_func + + Value: pos( + SimpleValue + + Ct(KeyValueList) / mark"table" + + ChainValue) + + SliceValue: SimpleValue + ChainValue + + StringChain: String * + (Ct((ColonCall + ColonSuffix) * ChainTail^-1) * Ct(InvokeArgs^-1))^-1 / flatten_string_chain + + String: Space * DoubleString + Space * SingleString + LuaString + SingleString: simple_string("'") + DoubleString: simple_string('"', true) + + LuaString: Cg(LuaStringOpen, "string_open") * Cb"string_open" * Break^-1 * + C((1 - Cmt(C(LuaStringClose) * Cb"string_open", check_lua_string))^0) * + LuaStringClose / mark"string" + + LuaStringOpen: sym"[" * P"="^0 * "[" / trim + LuaStringClose: "]" * P"="^0 * "]" + + Callable: pos(Name / mark"ref") + SelfName + VarArg + Parens / mark"parens" + Parens: sym"(" * SpaceBreak^0 * Exp * SpaceBreak^0 * sym")" + + FnArgs: symx"(" * SpaceBreak^0 * Ct(ExpList^-1) * SpaceBreak^0 * sym")" + sym"!" * -P"=" * Ct"" + + ChainTail: ChainItem^1 * ColonSuffix^-1 + ColonSuffix + + -- a list of funcalls and indexes on a callable + Chain: Callable * ChainTail / mark"chain" + + -- shorthand dot call for use in with statement + DotChain: + (sym"." * Cc(-1) * (_Name / mark"dot") * ChainTail^-1) / mark"chain" + + (sym"\\" * Cc(-1) * ( + (_Name * Invoke / mark"colon") * ChainTail^-1 + + (_Name / mark"colon_stub") + )) / mark"chain" + + ChainItem: + Invoke + + Slice + + symx"[" * Exp/mark"index" * sym"]" + + symx"." * _Name/mark"dot" + + ColonCall + + Slice: symx"[" * (SliceValue + Cc(1)) * sym"," * (SliceValue + Cc"") * + (sym"," * SliceValue)^-1 *sym"]" / mark"slice" + + ColonCall: symx"\\" * (_Name * Invoke) / mark"colon" + ColonSuffix: symx"\\" * _Name / mark"colon_stub" + + Invoke: FnArgs/mark"call" + + SingleString / wrap_func_arg + + DoubleString / wrap_func_arg + + TableValue: KeyValue + Ct(Exp) + + TableLit: sym"{" * Ct( + TableValueList^-1 * sym","^-1 * + (SpaceBreak * TableLitLine * (sym","^-1 * SpaceBreak * TableLitLine)^0 * sym","^-1)^-1 + ) * White * sym"}" / mark"table" + + TableValueList: TableValue * (sym"," * TableValue)^0 + TableLitLine: PushIndent * ((TableValueList * PopIndent) + (PopIndent * Cut)) + Space + + -- the unbounded table + TableBlockInner: Ct(KeyValueLine * (SpaceBreak^1 * KeyValueLine)^0) + TableBlock: SpaceBreak^1 * Advance * ensure(TableBlockInner, PopIndent) / mark"table" + + ClassDecl: key"class" * -P":" * (Assignable + Cc(nil)) * (key"extends" * PreventIndent * ensure(Exp, PopIndent) + C"")^-1 * (ClassBlock + Ct("")) / mark"class" + + ClassBlock: SpaceBreak^1 * Advance * + Ct(ClassLine * (SpaceBreak^1 * ClassLine)^0) * PopIndent + ClassLine: CheckIndent * (( + KeyValueList / mark"props" + + Statement / mark"stm" + + Exp / mark"stm" + ) * sym","^-1) + + Export: key"export" * ( + Cc"class" * ClassDecl + + op"*" + op"^" + + Ct(NameList) * (sym"=" * Ct(ExpListLow))^-1) / mark"export" + + KeyValue: (sym":" * -SomeSpace * Name * lpeg.Cp()) / self_assign + Ct((KeyName + sym"[" * Exp * sym"]" + DoubleString + SingleString) * symx":" * (Exp + TableBlock + SpaceBreak^1 * Exp)) + KeyValueList: KeyValue * (sym"," * KeyValue)^0 + KeyValueLine: CheckIndent * KeyValueList * sym","^-1 + + FnArgsDef: sym"(" * Ct(FnArgDefList^-1) * + (key"using" * Ct(NameList + Space * "nil") + Ct"") * + sym")" + Ct"" * Ct"" + + FnArgDefList: FnArgDef * (sym"," * FnArgDef)^0 * (sym"," * Ct(VarArg))^0 + Ct(VarArg) + FnArgDef: Ct((Name + SelfName) * (sym"=" * Exp)^-1) + + FunLit: FnArgsDef * + (sym"->" * Cc"slim" + sym"=>" * Cc"fat") * + (Body + Ct"") / mark"fndef" + + NameList: Name * (sym"," * Name)^0 + NameOrDestructure: Name + TableLit + AssignableNameList: NameOrDestructure * (sym"," * NameOrDestructure)^0 + + ExpList: Exp * (sym"," * Exp)^0 + ExpListLow: Exp * ((sym"," + sym";") * Exp)^0 + + InvokeArgs: -P"-" * (ExpList * (sym"," * (TableBlock + SpaceBreak * Advance * ArgBlock * TableBlock^-1) + TableBlock)^-1 + TableBlock) + ArgBlock: ArgLine * (sym"," * SpaceBreak * ArgLine)^0 * PopIndent + ArgLine: CheckIndent * ExpList + } + + file_grammar = White * g * White * -1 + + { + match: (str) => + local tree + _, err = xpcall (-> + tree = file_grammar\match str + ), (err) -> + debug.traceback err, 2 + + -- regular error, let it bubble up + if type(err) == "string" + return nil, err + + unless tree + local msg + pos = last_pos + + if err + node, msg = unpack err + msg = " " .. msg if msg + pos = node[-1] + + line_no = pos_to_line str, pos + line_str = get_line(str, line_no) or "" + return nil, err_msg\format msg or "", line_no, trim line_str + + tree + } + +{ + extract_line: extract_line, + + -- parse a string + -- returns tree, or nil and error message + string: (str) -> build_grammar!\match str +} + From eb42898b5b42b0150053b93d9b891672b2c7e6ac Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 28 Feb 2015 17:04:43 -0800 Subject: [PATCH 261/554] update rockspec, fixes #161 --- moonscript-dev-1.rockspec | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/moonscript-dev-1.rockspec b/moonscript-dev-1.rockspec index f1b4a1c5..00dd0544 100644 --- a/moonscript-dev-1.rockspec +++ b/moonscript-dev-1.rockspec @@ -7,6 +7,7 @@ source = { description = { summary = "A programmer friendly language that compiles to Lua", + detailed = "A programmer friendly language that compiles to Lua", homepage = "http://moonscript.org", maintainer = "Leaf Corcoran ", license = "MIT" @@ -37,6 +38,9 @@ build = { ["moonscript.errors"] = "moonscript/errors.lua", ["moonscript.line_tables"] = "moonscript/line_tables.lua", ["moonscript.parse"] = "moonscript/parse.lua", + ["moonscript.parse.env"] = "moonscript/parse/env.lua", + ["moonscript.parse.literals"] = "moonscript/parse/literals.lua", + ["moonscript.parse.util"] = "moonscript/parse/util.lua", ["moonscript.transform"] = "moonscript/transform.lua", ["moonscript.transform.destructure"] = "moonscript/transform/destructure.lua", ["moonscript.transform.names"] = "moonscript/transform/names.lua", From 9ae7df38dfcf44c3ff4f642e928e67e2f5b8ca65 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 28 Feb 2015 17:07:12 -0800 Subject: [PATCH 262/554] fix typo in docs #164 --- docs/standard_lib.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/standard_lib.md b/docs/standard_lib.md index f2686081..42cb7d4a 100644 --- a/docs/standard_lib.md +++ b/docs/standard_lib.md @@ -11,7 +11,7 @@ The entire library is currently contained in a single object. We can bring this `moon` object into scope by requiring `"moon"`. ```moon -require "moon" +moon = require "moon" -- `moon.p` is the debug printer moon.p { hello: "world" } ``` From f7beade09cfb522a4c7abc6c699899b564b4767e Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 28 Feb 2015 17:28:56 -0800 Subject: [PATCH 263/554] remove V cache #150 --- moonscript/parse/env.lua | 1 - moonscript/parse/env.moon | 1 - 2 files changed, 2 deletions(-) diff --git a/moonscript/parse/env.lua b/moonscript/parse/env.lua index 4a0adc33..6dbed84a 100644 --- a/moonscript/parse/env.lua +++ b/moonscript/parse/env.lua @@ -58,7 +58,6 @@ wrap_env = function(debug, fn) end if name:match("^[A-Z][A-Za-z0-9]*$") then local v = wrap_name(name) - rawset(self, name, v) return v end return error("unknown variable referenced: " .. tostring(name)) diff --git a/moonscript/parse/env.moon b/moonscript/parse/env.moon index 594d3e59..25dcc1e4 100644 --- a/moonscript/parse/env.moon +++ b/moonscript/parse/env.moon @@ -41,7 +41,6 @@ wrap_env = (debug, fn) -> if name\match"^[A-Z][A-Za-z0-9]*$" v = wrap_name name - rawset @, name, v return v error "unknown variable referenced: #{name}" From efc4d3dd0f29070ef3b5bd4867f8cf3f444df078 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 28 Feb 2015 18:47:27 -0800 Subject: [PATCH 264/554] update version --- moonscript/version.lua | 2 +- moonscript/version.moon | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/moonscript/version.lua b/moonscript/version.lua index ff223d3a..0d0b6f0f 100644 --- a/moonscript/version.lua +++ b/moonscript/version.lua @@ -1,4 +1,4 @@ -local version = "0.2.6" +local version = "0.3.0" return { version = version, print_version = function() diff --git a/moonscript/version.moon b/moonscript/version.moon index 156e240b..426abbb2 100644 --- a/moonscript/version.moon +++ b/moonscript/version.moon @@ -1,5 +1,5 @@ -version = "0.2.6" +version = "0.3.0" { version: version, From 2c44273b7776b73483277b24eda1e9edb0f388eb Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 28 Feb 2015 18:52:15 -0800 Subject: [PATCH 265/554] update changelog --- CHANGELOG.md | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 91e400eb..174b217c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,71 @@ +# MoonScript v0.3.0 (2015-2-28) + +## New Features + +* New [unused assignment linter](http://moonscript.org/reference/command_line.html#unused_variable_assigns) finds assignments that are never referenced after being defined. + +## Parsing Updates + +Whitespace parsing has been relaxed in a handful of locations: + +* You can put unrestricted whitespace/newlines after operator in a binary operator before writing the right hand side. The following are now valid: + +```moonscript +x = really_long_function! + + 2304 + +big_math = 123 / + 12 - + 43 * 17 + + +bool_exp = nice_shirt and cool_shoes or + skateboard and shades +``` + +* You can put unrestricted whitespace/newlines immediately after an opening parenthesis, and immediately before closing parenthesis. The following are now valid: + +```moonscript +hello = 100 + ( + var * 0.23 +) - 15 + + +funcall( + "height", "age", "weight" +) + + +takes_two_functions (-> + print "hello" +), -> + print "world" +``` + +* You can put unrestricted whitespace/newlines immediately after a `:` when defining a table literal. The following is now valid: + +```moonscript +x = { + hello: + call_a_function "football", "hut" +} +``` + +## Code Generation + +* Single value `import`/`destructure` compiles directly into single assignment + +## Bug Fixes + +* Some `moonc` command line flags were being ignored +* Linter would not report global reference when inside self assign in table +* Fixed an issue where parser would crash in Lpeg 0.12 when compiling hundreds of times per process + +## Misc + +* MoonScript parser now written in MoonScript + # MoonScript v0.2.6 (2014-6-18) ## Bug Fixes From f1b7f925074e54761968a12e783685246e7bff1a Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 28 Feb 2015 19:13:16 -0800 Subject: [PATCH 266/554] fix codeblock language --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 174b217c..c6b48044 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -142,7 +142,7 @@ where return can be cascaded into the body. **Before:** -```moonscript +```lua local _ _ = function() if test1 then @@ -173,7 +173,7 @@ end **After:** -```moonscript +```lua local _ _ = function() if test1 then From 50bf265e7359a681bd18a7cfcfd57f2b49a6e135 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 6 Mar 2015 09:58:13 -0800 Subject: [PATCH 267/554] bad local variable, fix #177 --- moonscript/parse.lua | 6 +++--- moonscript/parse.moon | 6 +++--- spec/error_rewriting_spec.moon | 8 ++++++++ 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 12f9062e..62044b7a 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -210,16 +210,16 @@ local build_grammar = wrap_env(debug_grammar, function() end if not (tree) then local msg - pos = last_pos + local err_pos = last_pos if err then local node node, msg = unpack(err) if msg then msg = " " .. msg end - pos = node[-1] + err_pos = node[-1] end - local line_no = pos_to_line(str, pos) + local line_no = pos_to_line(str, err_pos) local line_str = get_line(str, line_no) or "" return nil, err_msg:format(msg or "", line_no, trim(line_str)) end diff --git a/moonscript/parse.moon b/moonscript/parse.moon index a58d9cb2..3fb6bfa5 100644 --- a/moonscript/parse.moon +++ b/moonscript/parse.moon @@ -331,14 +331,14 @@ build_grammar = wrap_env debug_grammar, -> unless tree local msg - pos = last_pos + err_pos = last_pos if err node, msg = unpack err msg = " " .. msg if msg - pos = node[-1] + err_pos = node[-1] - line_no = pos_to_line str, pos + line_no = pos_to_line str, err_pos line_str = get_line(str, line_no) or "" return nil, err_msg\format msg or "", line_no, trim line_str diff --git a/spec/error_rewriting_spec.moon b/spec/error_rewriting_spec.moon index dfaab1b2..9978d1a2 100644 --- a/spec/error_rewriting_spec.moon +++ b/spec/error_rewriting_spec.moon @@ -60,4 +60,12 @@ describe "line map", -> -- print util.debug_posmap(posmap, moon_code, lua_code) assert.same {[1]: 7, [2]: 19, [7]: 19, [8]: 63}, posmap +describe "error reporting", -> + import to_lua from require "moonscript.base" + it "should compile bad code twice", -> + code, err = to_lua "{b=5}" + assert.truthy err + code, err2 = to_lua "{b=5}" + assert.same err, err2 + From fd278b8ccad6689014ad297f56713f411530fdd8 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 7 Mar 2015 08:19:10 -0800 Subject: [PATCH 268/554] version bump --- moonscript/version.lua | 2 +- moonscript/version.moon | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/moonscript/version.lua b/moonscript/version.lua index 0d0b6f0f..96e2ec83 100644 --- a/moonscript/version.lua +++ b/moonscript/version.lua @@ -1,4 +1,4 @@ -local version = "0.3.0" +local version = "0.3.1" return { version = version, print_version = function() diff --git a/moonscript/version.moon b/moonscript/version.moon index 426abbb2..6e909479 100644 --- a/moonscript/version.moon +++ b/moonscript/version.moon @@ -1,5 +1,5 @@ -version = "0.3.0" +version = "0.3.1" { version: version, From 640d30f80d0b6f2a2795f17ccbad1c8ac46dcb3e Mon Sep 17 00:00:00 2001 From: mpeterv Date: Thu, 12 Mar 2015 11:09:17 +0300 Subject: [PATCH 269/554] fix crash in moonc on Lua 5.3 --- bin/moonc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/moonc b/bin/moonc index bc8ed20b..5de57204 100755 --- a/bin/moonc +++ b/bin/moonc @@ -54,6 +54,7 @@ function log_msg(...) end local moonc = require("moonscript.cmd.moonc") +local util = require "moonscript.util" local mkdir = moonc.mkdir local normalize_dir = moonc.normalize_dir local parse_dir = moonc.parse_dir @@ -309,7 +310,7 @@ elseif opts.l then end else for _, tuple in ipairs(files) do - local fname, target = unpack(tuple) + local fname, target = util.unpack(tuple) if opts.o then target = opts.o end From 13dda4e9ba26d44576c26a7043ad6a913be655a4 Mon Sep 17 00:00:00 2001 From: mpeterv Date: Thu, 12 Mar 2015 11:22:18 +0300 Subject: [PATCH 270/554] Upgrade to busted 2.0.rc7 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 346cc94e..55a8e747 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ install: - sudo apt-get install luarocks - mkdir -p ~/.luarocks - echo 'rocks_servers = { "http://rocks.moonscript.org" }' > ~/.luarocks/config.lua - - sudo luarocks install https://rocks.moonscript.org/manifests/olivine-labs/busted-1.11.1-1.rockspec + - sudo luarocks install https://rocks.moonscript.org/manifests/olivine-labs/busted-2.0.rc7-0.rockspec - sudo luarocks make script: busted From 28eff692d99057286864e8c217a46c118a56643c Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Mon, 16 Mar 2015 21:46:57 -0700 Subject: [PATCH 271/554] update changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c6b48044..e866ee25 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,10 @@ +# MoonScript v0.3.1 (2015-3-07) + +## Bug Fixes + +* Fixed a bug where an error from a previous compile would prevent the compiler from running again + # MoonScript v0.3.0 (2015-2-28) ## New Features From f08477d3d6e7d2807c28fb70746351979745c505 Mon Sep 17 00:00:00 2001 From: mpeterv Date: Thu, 12 Mar 2015 20:28:16 +0300 Subject: [PATCH 272/554] fix package.moonpath generation Do not use paths from package.path which do not end in .lua --- moonscript/base.lua | 10 ++++++---- moonscript/base.moon | 8 ++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/moonscript/base.lua b/moonscript/base.lua index 9c74de4b..379b6bc7 100644 --- a/moonscript/base.lua +++ b/moonscript/base.lua @@ -18,14 +18,16 @@ local dirsep, line_tables, create_moonpath, to_lua, moon_loader, loadstring, loa dirsep = "/" line_tables = require("moonscript.line_tables") create_moonpath = function(package_path) - local paths = split(package_path, ";") - for i, path in ipairs(paths) do + local moonpaths = { } + local _list_0 = split(package.path, ";") + for _index_0 = 1, #_list_0 do + local path = _list_0[_index_0] local p = path:match("^(.-)%.lua$") if p then - paths[i] = p .. ".moon" + insert(moonpaths, p .. ".moon") end end - return concat(paths, ";") + return concat(moonpaths, ";") end to_lua = function(text, options) if options == nil then diff --git a/moonscript/base.moon b/moonscript/base.moon index 371628cc..8cfbfb3f 100644 --- a/moonscript/base.moon +++ b/moonscript/base.moon @@ -13,11 +13,11 @@ line_tables = require "moonscript.line_tables" -- create moon path package from lua package path create_moonpath = (package_path) -> - paths = split package_path, ";" - for i, path in ipairs paths + moonpaths = {} + for path in *split package.path, ";" p = path\match "^(.-)%.lua$" - if p then paths[i] = p..".moon" - concat paths, ";" + if p then insert moonpaths, p..".moon" + concat moonpaths, ";" to_lua = (text, options={}) -> if "string" != type text From 0ccd5e3ca4addb1c722aa3833b27d070808d5bf9 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Mon, 16 Mar 2015 23:54:33 -0700 Subject: [PATCH 273/554] restore argument, make more moonscripty, add spec #176 --- moonscript/base.lua | 33 +++++++++++++++++++++++++-------- moonscript/base.moon | 10 +++++----- spec/moonscript_spec.moon | 8 ++++++++ 3 files changed, 38 insertions(+), 13 deletions(-) create mode 100644 spec/moonscript_spec.moon diff --git a/moonscript/base.lua b/moonscript/base.lua index 379b6bc7..e436678a 100644 --- a/moonscript/base.lua +++ b/moonscript/base.lua @@ -18,14 +18,30 @@ local dirsep, line_tables, create_moonpath, to_lua, moon_loader, loadstring, loa dirsep = "/" line_tables = require("moonscript.line_tables") create_moonpath = function(package_path) - local moonpaths = { } - local _list_0 = split(package.path, ";") - for _index_0 = 1, #_list_0 do - local path = _list_0[_index_0] - local p = path:match("^(.-)%.lua$") - if p then - insert(moonpaths, p .. ".moon") + local moonpaths + do + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = split(package_path, ";") + for _index_0 = 1, #_list_0 do + local _continue_0 = false + repeat + local path = _list_0[_index_0] + local prefix = path:match("^(.-)%.lua$") + if not (prefix) then + _continue_0 = true + break + end + local _value_0 = prefix .. ".moon" + _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 + _continue_0 = true + until true + if not _continue_0 then + break + end end + moonpaths = _accum_0 end return concat(moonpaths, ";") end @@ -134,5 +150,6 @@ return { dirsep = dirsep, dofile = dofile, loadfile = loadfile, - loadstring = loadstring + loadstring = loadstring, + create_moonpath = create_moonpath } diff --git a/moonscript/base.moon b/moonscript/base.moon index 8cfbfb3f..b2068f0b 100644 --- a/moonscript/base.moon +++ b/moonscript/base.moon @@ -13,10 +13,10 @@ line_tables = require "moonscript.line_tables" -- create moon path package from lua package path create_moonpath = (package_path) -> - moonpaths = {} - for path in *split package.path, ";" - p = path\match "^(.-)%.lua$" - if p then insert moonpaths, p..".moon" + moonpaths = for path in *split package_path, ";" + prefix = path\match "^(.-)%.lua$" + continue unless prefix + prefix .. ".moon" concat moonpaths, ";" to_lua = (text, options={}) -> @@ -103,6 +103,6 @@ remove_loader = -> { _NAME: "moonscript" :insert_loader, :remove_loader, :to_lua, :moon_loader, :dirsep, - :dofile, :loadfile, :loadstring + :dofile, :loadfile, :loadstring, :create_moonpath } diff --git a/spec/moonscript_spec.moon b/spec/moonscript_spec.moon new file mode 100644 index 00000000..8db55585 --- /dev/null +++ b/spec/moonscript_spec.moon @@ -0,0 +1,8 @@ +-- moonscript module + +describe "moonscript.base", -> + it "should create moonpath", -> + path = ";./?.lua;/usr/share/lua/5.1/?.lua;/usr/share/lua/5.1/?/init.lua;/usr/lib/lua/5.1/?.luac;/home/leafo/.luarocks/lua/5.1/?.lua" + import create_moonpath from require "moonscript.base" + assert.same "./?.moon;/usr/share/lua/5.1/?.moon;/usr/share/lua/5.1/?/init.moon;/home/leafo/.luarocks/lua/5.1/?.moon", create_moonpath(path) + From fb791ed4027274937e1af78df084d9b636e1c6e1 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Mon, 1 Jun 2015 22:32:36 -0700 Subject: [PATCH 274/554] version bump --- CHANGELOG.md | 6 ++++++ moonscript/version.lua | 2 +- moonscript/version.moon | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e866ee25..b78411af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,10 @@ +# MoonScript v0.3.2 (2015-6-01) + +## Bug Fixes + +* `package.moonpath` geneator does not use paths that don't end in `lua` + # MoonScript v0.3.1 (2015-3-07) ## Bug Fixes diff --git a/moonscript/version.lua b/moonscript/version.lua index 96e2ec83..352d7a98 100644 --- a/moonscript/version.lua +++ b/moonscript/version.lua @@ -1,4 +1,4 @@ -local version = "0.3.1" +local version = "0.3.2" return { version = version, print_version = function() diff --git a/moonscript/version.moon b/moonscript/version.moon index 6e909479..018d1c8c 100644 --- a/moonscript/version.moon +++ b/moonscript/version.moon @@ -1,5 +1,5 @@ -version = "0.3.1" +version = "0.3.2" { version: version, From e46fb70d700a7d77f616d09025bc6e4cf6813626 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Mon, 8 Jun 2015 21:07:23 -0700 Subject: [PATCH 275/554] expose api for building custom grammars --- moonscript/parse.lua | 15 ++++++++++----- moonscript/parse.moon | 15 +++++++++------ 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 62044b7a..1ae66f32 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -32,7 +32,7 @@ do local _obj_0 = require("moonscript.parse.util") Indent, Cut, ensure, extract_line, mark, pos, flatten_or_mark, is_assignable, check_assignable, format_assign, format_single_assign, sym, symx, simple_string, wrap_func_arg, flatten_func, flatten_string_chain, wrap_decorator, check_lua_string, self_assign = _obj_0.Indent, _obj_0.Cut, _obj_0.ensure, _obj_0.extract_line, _obj_0.mark, _obj_0.pos, _obj_0.flatten_or_mark, _obj_0.is_assignable, _obj_0.check_assignable, _obj_0.format_assign, _obj_0.format_single_assign, _obj_0.sym, _obj_0.symx, _obj_0.simple_string, _obj_0.wrap_func_arg, _obj_0.flatten_func, _obj_0.flatten_string_chain, _obj_0.wrap_decorator, _obj_0.check_lua_string, _obj_0.self_assign end -local build_grammar = wrap_env(debug_grammar, function() +local build_grammar = wrap_env(debug_grammar, function(root) local _indent = Stack(0) local _do_stack = Stack(0) local last_pos = 0 @@ -103,8 +103,8 @@ local build_grammar = wrap_env(debug_grammar, function() local SelfName = Space * "@" * ("@" * (_Name / mark("self_class") + Cc("self.__class")) + _Name / mark("self") + Cc("self")) local KeyName = SelfName + Space * _Name / mark("key_literal") local VarArg = Space * P("...") / trim - local g = P({ - File, + return P({ + root or File, File = Shebang ^ -1 * (Block + Ct("")), Block = Ct(Line * (Break ^ 1 * Line) ^ 0), CheckIndent = Cmt(Indent, check_indent), @@ -196,6 +196,10 @@ local build_grammar = wrap_env(debug_grammar, function() ArgBlock = ArgLine * (sym(",") * SpaceBreak * ArgLine) ^ 0 * PopIndent, ArgLine = CheckIndent * ExpList }) +end) +local file_parser +file_parser = function() + local g = build_grammar() local file_grammar = White * g * White * -1 return { match = function(self, str) @@ -226,10 +230,11 @@ local build_grammar = wrap_env(debug_grammar, function() return tree end } -end) +end return { extract_line = extract_line, + build_grammar = build_grammar, string = function(str) - return build_grammar():match(str) + return file_parser():match(str) end } diff --git a/moonscript/parse.moon b/moonscript/parse.moon index 3fb6bfa5..5c0885e8 100644 --- a/moonscript/parse.moon +++ b/moonscript/parse.moon @@ -32,7 +32,7 @@ Num = Space * (Num / (v) -> {"number", v}) } = require "moonscript.parse.util" -build_grammar = wrap_env debug_grammar, -> +build_grammar = wrap_env debug_grammar, (root) -> _indent = Stack 0 _do_stack = Stack 0 @@ -101,8 +101,8 @@ build_grammar = wrap_env debug_grammar, -> KeyName = SelfName + Space * _Name / mark"key_literal" VarArg = Space * P"..." / trim - g = P { - File + P { + root or File File: Shebang^-1 * (Block + Ct"") Block: Ct(Line * (Break^1 * Line)^0) CheckIndent: Cmt(Indent, check_indent), -- validates line is in correct indent @@ -315,6 +315,8 @@ build_grammar = wrap_env debug_grammar, -> ArgLine: CheckIndent * ExpList } +file_parser = -> + g = build_grammar! file_grammar = White * g * White * -1 { @@ -346,10 +348,11 @@ build_grammar = wrap_env debug_grammar, -> } { - extract_line: extract_line, + :extract_line + :build_grammar - -- parse a string + -- parse a string as a file -- returns tree, or nil and error message - string: (str) -> build_grammar!\match str + string: (str) -> file_parser!\match str } From 32239c8455611bf8e9d69f87c894bd34427bd3ca Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Mon, 8 Jun 2015 21:46:28 -0700 Subject: [PATCH 276/554] rewrite bin/moon in moonscript --- Makefile | 3 + bin/moon | 214 ++++++++++++++++++++++++++------------------------ bin/moon.moon | 116 +++++++++++++++++++++++++++ 3 files changed, 229 insertions(+), 104 deletions(-) create mode 100644 bin/moon.moon diff --git a/Makefile b/Makefile index 9a44cfec..13a1eba8 100644 --- a/Makefile +++ b/Makefile @@ -14,6 +14,9 @@ global: compile: lua5.1 bin/moonc moon/ moonscript/ + echo "#!/usr/bin/env lua" > bin/moon + lua5.1 bin/moonc -p bin/moon.moon >> bin/moon + echo "-- vim: set filetype=lua:" >> bin/moon watch: moonc moon/ moonscript/ && moonc -w moon/ moonscript/ diff --git a/bin/moon b/bin/moon index b6ef27fe..a4892bd3 100755 --- a/bin/moon +++ b/bin/moon @@ -1,16 +1,13 @@ #!/usr/bin/env lua - -require "alt_getopt" -local moonscript = require "moonscript.base" - -local util = require "moonscript.util" -local errors = require "moonscript.errors" - +require("alt_getopt") +local moonscript = require("moonscript.base") +local util = require("moonscript.util") +local errors = require("moonscript.errors") local unpack = util.unpack - --- moonloader and repl -local opts, ind = alt_getopt.get_opts(arg, "cvhd", { version = "v", help = "h" }) - +local opts, ind = alt_getopt.get_opts(arg, "cvhd", { + version = "v", + help = "h" +}) local help = [=[Usage: %s [options] [script [args]] -h Print this message @@ -18,99 +15,108 @@ local help = [=[Usage: %s [options] [script [args]] -c Collect and print code coverage -v Print version ]=] - -local function print_err(...) - local msg = table.concat({...}, "\t") - io.stderr:write(msg .. "\n") -end - -local function print_help(err) - if err then print("Error: "..err) end - print(help:format(arg[0])) - os.exit() -end - -if opts.h then print_help() end - -if opts.v then - local v = require "moonscript.version" - v.print_version() - os.exit() -end - -local script_fname = arg[ind] -if not script_fname then - print_help("repl not yet supported") - return +local print_err +print_err = function(...) + local msg = table.concat((function(...) + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local v = _list_0[_index_0] + _accum_0[_len_0] = tostring(v) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)(...), "\t") + return io.stderr:write(msg .. "\n") end - -local new_arg = { - [-1] = arg[0], - [0] = arg[ind], - select(ind + 1, unpack(arg)) -} - -local moonscript_chunk, lua_parse_error -local passed, err = pcall(function() - moonscript_chunk, lua_parse_error = moonscript.loadfile(script_fname, { implicitly_return_root = false }) -end) - -if not passed then - print_err(err) - os.exit(1) +local print_help +print_help = function(err) + help = help:format(arg[0]) + if err then + print_err(err) + print_err(help) + else + print(help) + end + return os.exit() end - -if not moonscript_chunk then - if lua_parse_error then - print_err(lua_parse_error) - else - print_err("Can't find file: " .. script_fname) - end - os.exit(1) -end - -util.getfenv(moonscript_chunk).arg = new_arg - -local function run_chunk() - moonscript.insert_loader() - moonscript_chunk(unpack(new_arg)) - moonscript.remove_loader() -end - -if not opts.d then - local err, trace - local cov - - if opts.c then - local coverage = require "moonscript.cmd.coverage" - cov = coverage.CodeCoverage() - cov:start() - end - - xpcall(run_chunk, function(_err) - err = _err - trace = debug.traceback("", 2) - end) - - if err then - local truncated = errors.truncate_traceback(util.trim(trace)) - local rewritten = errors.rewrite_traceback(truncated, err) - - if rewritten then - print_err(rewritten) - else - -- faield to rewrite, show original - print_err(table.concat({ - err, - util.trim(trace) - }, "\n")) - end - else - if cov then - cov:stop() - cov:print_results() - end - end -else - run_chunk() +local run +run = function() + if opts.h then + print_help() + end + if opts.v then + require("moonscript.version").print_version() + os.exit() + end + local script_fname = arg[ind] + if not (script_fname) then + print_help("repl not yet supported") + end + local new_arg = { + [-1] = arg[0], + [0] = arg[ind], + select(ind + 1, unpack(arg)) + } + local moonscript_chunk, lua_parse_error + local passed, err = pcall(function() + moonscript_chunk, lua_parse_error = moonscript.loadfile(script_fname, { + implicitly_return_root = false + }) + end) + if not (passed) then + print_err(err) + os.exit(1) + end + if not (moonscript_chunk) then + if lua_parse_error then + print_err(lua_parse_error) + else + print_err("Can't file file: " .. tostring(script_fname)) + end + os.exit(1) + end + util.getfenv(moonscript_chunk).arg = new_arg + local run_chunk + run_chunk = function() + moonscript.insert_loader() + moonscript_chunk(unpack(new_arg)) + return moonscript.remove_loader() + end + if opts.d then + return run_chunk() + end + local err, trace, cov + if opts.c then + print("starting coverage") + local coverage = require("moonscript.cmd.coverage") + cov = coverage.CodeCoverage() + cov:start() + end + xpcall(run_chunk, function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if err then + local truncated = errors.truncate_traceback(util.trim(trace)) + local rewritten = errors.rewrite_traceback(truncated, err) + if rewritten then + return print_err(rewritten) + else + return print_err(table.concat({ + err, + util.trim(trace) + }, "\n")) + end + else + if cov then + cov:stop() + return cov:print_results() + end + end end +return run() +-- vim: set filetype=lua: diff --git a/bin/moon.moon b/bin/moon.moon new file mode 100644 index 00000000..853cf19b --- /dev/null +++ b/bin/moon.moon @@ -0,0 +1,116 @@ + +require "alt_getopt" + +moonscript = require "moonscript.base" +util = require "moonscript.util" +errors = require "moonscript.errors" + +unpack = util.unpack + +opts, ind = alt_getopt.get_opts arg, "cvhd", { + version: "v" + help: "h" +} + +help = [=[Usage: %s [options] [script [args]] + + -h Print this message + -d Disable stack trace rewriting + -c Collect and print code coverage + -v Print version +]=] + + +print_err = (...) -> + msg = table.concat [tostring v for v in *{...}], "\t" + io.stderr\write msg .. "\n" + +print_help = (err) -> + help = help\format arg[0] + + if err + print_err err + print_err help + else + print help + + os.exit! + +run = -> + if opts.h + print_help! + + if opts.v + require("moonscript.version").print_version! + os.exit! + + script_fname = arg[ind] + + unless script_fname + print_help "repl not yet supported" + + new_arg = { + [-1]: arg[0], + [0]: arg[ind], + select ind + 1, unpack arg + } + + local moonscript_chunk, lua_parse_error + + passed, err = pcall -> + moonscript_chunk, lua_parse_error = moonscript.loadfile script_fname, { + implicitly_return_root: false + } + + unless passed + print_err err + os.exit 1 + + unless moonscript_chunk + if lua_parse_error + print_err lua_parse_error + else + print_err "Can't file file: #{script_fname}" + + os.exit 1 + + util.getfenv(moonscript_chunk).arg = new_arg + + run_chunk = -> + moonscript.insert_loader! + moonscript_chunk unpack new_arg + moonscript.remove_loader! + + if opts.d + return run_chunk! + + local err, trace, cov + + if opts.c + print "starting coverage" + coverage = require "moonscript.cmd.coverage" + cov = coverage.CodeCoverage! + cov\start! + + xpcall run_chunk, (_err) -> + err = _err + trace = debug.traceback "", 2 + + if err + truncated = errors.truncate_traceback util.trim trace + rewritten = errors.rewrite_traceback truncated, err + + if rewritten + print_err rewritten + else + -- failed to rewrite, show original + print_err table.concat { + err, + util.trim trace + }, "\n" + else + if cov + cov\stop! + cov\print_results! + +run! From 1bd8b0336e210a2f06f4d9e48dc5742261a283a3 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Mon, 8 Jun 2015 21:50:52 -0700 Subject: [PATCH 277/554] pass last pos through state table --- moonscript/parse.lua | 13 ++++++++----- moonscript/parse.moon | 15 ++++++++++----- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 1ae66f32..1ec4f115 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -35,10 +35,12 @@ end local build_grammar = wrap_env(debug_grammar, function(root) local _indent = Stack(0) local _do_stack = Stack(0) - local last_pos = 0 + local state = { + last_pos = 0 + } local check_indent check_indent = function(str, pos, indent) - last_pos = pos + state.last_pos = pos return _indent:top() == indent end local advance_indent @@ -103,7 +105,7 @@ local build_grammar = wrap_env(debug_grammar, function(root) local SelfName = Space * "@" * ("@" * (_Name / mark("self_class") + Cc("self.__class")) + _Name / mark("self") + Cc("self")) local KeyName = SelfName + Space * _Name / mark("key_literal") local VarArg = Space * P("...") / trim - return P({ + local g = P({ root or File, File = Shebang ^ -1 * (Block + Ct("")), Block = Ct(Line * (Break ^ 1 * Line) ^ 0), @@ -196,10 +198,11 @@ local build_grammar = wrap_env(debug_grammar, function(root) ArgBlock = ArgLine * (sym(",") * SpaceBreak * ArgLine) ^ 0 * PopIndent, ArgLine = CheckIndent * ExpList }) + return g, state end) local file_parser file_parser = function() - local g = build_grammar() + local g, state = build_grammar() local file_grammar = White * g * White * -1 return { match = function(self, str) @@ -214,7 +217,7 @@ file_parser = function() end if not (tree) then local msg - local err_pos = last_pos + local err_pos = state.last_pos if err then local node node, msg = unpack(err) diff --git a/moonscript/parse.moon b/moonscript/parse.moon index 5c0885e8..0dd07a02 100644 --- a/moonscript/parse.moon +++ b/moonscript/parse.moon @@ -36,10 +36,13 @@ build_grammar = wrap_env debug_grammar, (root) -> _indent = Stack 0 _do_stack = Stack 0 - last_pos = 0 -- last pos we saw, used to report error location + state = { + -- last pos we saw, used to report error location + last_pos: 0 + } check_indent = (str, pos, indent) -> - last_pos = pos + state.last_pos = pos _indent\top! == indent advance_indent = (str, pos, indent) -> @@ -101,7 +104,7 @@ build_grammar = wrap_env debug_grammar, (root) -> KeyName = SelfName + Space * _Name / mark"key_literal" VarArg = Space * P"..." / trim - P { + g = P { root or File File: Shebang^-1 * (Block + Ct"") Block: Ct(Line * (Break^1 * Line)^0) @@ -315,8 +318,10 @@ build_grammar = wrap_env debug_grammar, (root) -> ArgLine: CheckIndent * ExpList } + g, state + file_parser = -> - g = build_grammar! + g, state = build_grammar! file_grammar = White * g * White * -1 { @@ -333,7 +338,7 @@ file_parser = -> unless tree local msg - err_pos = last_pos + err_pos = state.last_pos if err node, msg = unpack err From 9e98affc1d0fda5ed68a845b083eac3db8ad63f3 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Mon, 8 Jun 2015 22:03:11 -0700 Subject: [PATCH 278/554] put bin in lint --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 13a1eba8..a374fb3e 100644 --- a/Makefile +++ b/Makefile @@ -22,4 +22,4 @@ watch: moonc moon/ moonscript/ && moonc -w moon/ moonscript/ lint: - moonc -l moonscript moon + moonc -l moonscript moon bin From b0904c170cae82d2b0947f058e7192bce07f0593 Mon Sep 17 00:00:00 2001 From: nymphium Date: Thu, 13 Aug 2015 18:02:30 +0900 Subject: [PATCH 279/554] added Lua5.3's new operators --- moonscript/compile/value.lua | 3 +++ moonscript/compile/value.moon | 3 +++ moonscript/parse.lua | 6 +++--- moonscript/parse.moon | 5 +++-- 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/moonscript/compile/value.lua b/moonscript/compile/value.lua index 8f8e8f23..c71a45b3 100644 --- a/moonscript/compile/value.lua +++ b/moonscript/compile/value.lua @@ -276,6 +276,9 @@ return { number = function(self, node) return node[2] end, + bitnot = function(self, node) + return self:line("~", self:value(node[2])) + end, length = function(self, node) return self:line("#", self:value(node[2])) end, diff --git a/moonscript/compile/value.moon b/moonscript/compile/value.moon index 515fed87..d1c9fae1 100644 --- a/moonscript/compile/value.moon +++ b/moonscript/compile/value.moon @@ -166,6 +166,9 @@ string_chars = { number: (node) => node[2] + bitnot: (node) => + @line "~", @value node[2] + length: (node) => @line "#", @value node[2] diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 1ec4f115..920668bb 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -145,12 +145,12 @@ local build_grammar = wrap_env(debug_grammar, function(root) 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"), - CharOperators = Space * C(S("+-*/%^><")), - WordOperators = op("or") + op("and") + op("<=") + op(">=") + op("~=") + op("!=") + op("==") + op(".."), + CharOperators = Space * C(S("+-*/%^><|&")), + WordOperators = op("or") + op("and") + op("<=") + op(">=") + op("~=") + op("!=") + op("==") + op("..") + op("<<") + op(">>") + op("//"), BinaryOperator = (WordOperators + CharOperators) * SpaceBreak ^ 0, Assignable = Cmt(DotChain + Chain, check_assignable) + Name + SelfName, Exp = Ct(Value * (BinaryOperator * Value) ^ 0) / flatten_or_mark("exp"), - SimpleValue = If + Unless + Switch + With + ClassDecl + ForEach + For + While + Cmt(Do, check_do) + sym("-") * -SomeSpace * Exp / mark("minus") + sym("#") * Exp / mark("length") + key("not") * Exp / mark("not") + TblComprehension + TableLit + Comprehension + FunLit + Num, + SimpleValue = If + Unless + Switch + With + ClassDecl + ForEach + For + While + Cmt(Do, check_do) + sym("-") * -SomeSpace * Exp / mark("minus") + sym("#") * Exp / mark("length") + sym("~") * Exp / mark("bitnot") + key("not") * Exp / mark("not") + TblComprehension + TableLit + Comprehension + FunLit + Num, ChainValue = StringChain + ((Chain + DotChain + Callable) * Ct(InvokeArgs ^ -1)) / flatten_func, Value = pos(SimpleValue + Ct(KeyValueList) / mark("table") + ChainValue), SliceValue = SimpleValue + ChainValue, diff --git a/moonscript/parse.moon b/moonscript/parse.moon index 0dd07a02..ce4b221e 100644 --- a/moonscript/parse.moon +++ b/moonscript/parse.moon @@ -179,8 +179,8 @@ build_grammar = wrap_env debug_grammar, (root) -> 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" - CharOperators: Space * C(S"+-*/%^><") - WordOperators: op"or" + op"and" + op"<=" + op">=" + op"~=" + op"!=" + op"==" + op".." + CharOperators: Space * C(S"+-*/%^><|&") + WordOperators: op"or" + op"and" + op"<=" + op">=" + op"~=" + op"!=" + op"==" + op".." + op"<<" + op">>" + op"//" BinaryOperator: (WordOperators + CharOperators) * SpaceBreak^0 Assignable: Cmt(DotChain + Chain, check_assignable) + Name + SelfName @@ -195,6 +195,7 @@ build_grammar = wrap_env debug_grammar, (root) -> Cmt(Do, check_do) + sym"-" * -SomeSpace * Exp / mark"minus" + sym"#" * Exp / mark"length" + + sym"~" * Exp / mark"bitnot" + key"not" * Exp / mark"not" + TblComprehension + TableLit + From db523926d3ec9ceddc7eaa4e0d72ec72f41fb7e7 Mon Sep 17 00:00:00 2001 From: nymphium Date: Thu, 13 Aug 2015 18:06:03 +0900 Subject: [PATCH 280/554] make it choice /usr/bin/lua, not lua5.1 --- Makefile | 4 ++-- moon/init.moon | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index a374fb3e..c620a2ef 100644 --- a/Makefile +++ b/Makefile @@ -13,9 +13,9 @@ global: sudo luarocks make moonscript-dev-1.rockspec compile: - lua5.1 bin/moonc moon/ moonscript/ + lua bin/moonc moon/ moonscript/ echo "#!/usr/bin/env lua" > bin/moon - lua5.1 bin/moonc -p bin/moon.moon >> bin/moon + lua bin/moonc -p bin/moon.moon >> bin/moon echo "-- vim: set filetype=lua:" >> bin/moon watch: diff --git a/moon/init.moon b/moon/init.moon index ef07bbaf..5817bc55 100644 --- a/moon/init.moon +++ b/moon/init.moon @@ -41,7 +41,7 @@ debug = setmetatable { -- run a function with scope injected before its function environment run_with_scope = (fn, scope, ...) -> - old_env = getfenv fn + old_env = util.getfenv fn env = setmetatable {}, { __index: (name) => val = scope[name] @@ -50,7 +50,7 @@ run_with_scope = (fn, scope, ...) -> else old_env[name] } - setfenv fn, env + util.setfenv fn, env fn ... -- wrap obj such that calls to methods do not need a reference to self From 0d330c8416614c3337bfb9c321f1482ab5ab8093 Mon Sep 17 00:00:00 2001 From: nymphium Date: Fri, 21 Aug 2015 21:24:31 +0900 Subject: [PATCH 281/554] LUA=lua5.1 as default, and detect luarocks and LUA_{C,}PATH --- Makefile | 25 ++++++++++++++++++++----- moonscript/parse.moon | 2 +- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index c620a2ef..d4fb0945 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,18 @@ +LUA ?= lua5.1 +LUAROCKS ?= luarocks + +ifneq ($(LUA),lua) + LUA_VERSION = $(shell echo $(LUA) | sed -e "s/lua\(.*\)/\1/") + LUAROCKS = luarocks-$(LUA_VERSION) + LUA_PATH_MAKE = $(shell echo "${LUA_PATH}" | sed -e "s/[0-9]\.[0-9]/$(LUA_VERSION)/g") + LUA_CPATH_MAKE = $(shell echo "${LUA_CPATH}" | sed -e "s/[0-9]\.[0-9]/$(LUA_VERSION)/g") +endif + +ifeq ($(LUA),luajit) + LUAROCKS = luarocks-5.1 +endif + + .PHONY: test local compile watch lint test_safe test: @@ -7,15 +22,15 @@ test_safe: busted -p "_spec.lua$$" local: compile - luarocks make --local moonscript-dev-1.rockspec + LUA_PATH=$(LUA_PATH_MAKE) LUA_CPATH=$(LUA_CPATH_MAKE) $(LUAROCKS) make --local moonscript-dev-1.rockspec global: - sudo luarocks make moonscript-dev-1.rockspec + sudo LUA_PATH=$(LUA_PATH_MAKE) LUA_CPATH=$(LUA_CPATH_MAKE) $(LUAROCKS) make moonscript-dev-1.rockspec -compile: - lua bin/moonc moon/ moonscript/ +compile: init + LUA_PATH=$(LUA_PATH_MAKE) LUA_CPATH=$(LUA_CPATH_MAKE) $(LUA) bin/moonc moon/ moonscript/ echo "#!/usr/bin/env lua" > bin/moon - lua bin/moonc -p bin/moon.moon >> bin/moon + $(LUA) bin/moonc -p bin/moon.moon >> bin/moon echo "-- vim: set filetype=lua:" >> bin/moon watch: diff --git a/moonscript/parse.moon b/moonscript/parse.moon index 0dd07a02..24581a50 100644 --- a/moonscript/parse.moon +++ b/moonscript/parse.moon @@ -291,7 +291,7 @@ build_grammar = wrap_env debug_grammar, (root) -> op"*" + op"^" + Ct(NameList) * (sym"=" * Ct(ExpListLow))^-1) / mark"export" - KeyValue: (sym":" * -SomeSpace * Name * lpeg.Cp()) / self_assign + Ct((KeyName + sym"[" * Exp * sym"]" + DoubleString + SingleString) * symx":" * (Exp + TableBlock + SpaceBreak^1 * Exp)) + KeyValue: (sym":" * -SomeSpace * Name * lpeg.Cp!) / self_assign + Ct((KeyName + sym"[" * Exp * sym"]" + DoubleString + SingleString) * symx":" * (Exp + TableBlock + SpaceBreak^1 * Exp)) KeyValueList: KeyValue * (sym"," * KeyValue)^0 KeyValueLine: CheckIndent * KeyValueList * sym","^-1 From b78cdab10b37e6caeffd6d44c48696b30fb58b2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Davidovi=C4=87?= Date: Sat, 5 Sep 2015 16:59:40 +0200 Subject: [PATCH 282/554] Fix bug regarding nested `with` blocks Nested `with` blocks, when the node being used for the block is referenced from the enclosing `with` block using the short-dot syntax, do not produce the correct output. This happens because `scoped_var` is being set at the wrong place. Fixes #187 (and #197, its dupe). --- moonscript/transform.lua | 4 ++-- moonscript/transform.moon | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/moonscript/transform.lua b/moonscript/transform.lua index c2499296..d81a6100 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -713,11 +713,11 @@ Statement = Transformer({ end scope_name = scope_name or NameProxy("with") return build["do"]({ + copy_scope and build.assign_one(scope_name, exp) or NOOP, + named_assign or NOOP, Run(function(self) return self:set("scope_var", scope_name) end), - copy_scope and build.assign_one(scope_name, exp) or NOOP, - named_assign or NOOP, build.group(block), (function() if ret then diff --git a/moonscript/transform.moon b/moonscript/transform.moon index 059f7d84..8b47c2db 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -418,9 +418,9 @@ Statement = Transformer { scope_name or= NameProxy "with" build.do { - Run => @set "scope_var", scope_name copy_scope and build.assign_one(scope_name, exp) or NOOP named_assign or NOOP + Run => @set "scope_var", scope_name build.group block if ret From 5ae8ffaed74aa9ec5695caaf229af09835b1eb6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Davidovi=C4=87?= Date: Sat, 5 Sep 2015 17:01:28 +0200 Subject: [PATCH 283/554] Add tests for nested `with` blocks Added two tests that test the behavior of nested `with` blocks. When a nested `with` block is started, using a variable referenced from the enclosing one, expected behavior is to change the short-dot syntax scope to the newly-referenced variable. --- spec/inputs/with.moon | 12 +++++++++++- spec/outputs/with.lua | 20 ++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/spec/inputs/with.moon b/spec/inputs/with.moon index 54aa5091..16f3574d 100644 --- a/spec/inputs/with.moon +++ b/spec/inputs/with.moon @@ -93,6 +93,16 @@ do with k.j = "jo" print \upper! +do + with a + print .b + -- nested `with`s should change the scope correctly + with .c + print .d - +do + with a + -- nested `with`s with assignments should change the scope correctly + with .b = 2 + print .c diff --git a/spec/outputs/with.lua b/spec/outputs/with.lua index d1d104a0..62fbb1ca 100644 --- a/spec/outputs/with.lua +++ b/spec/outputs/with.lua @@ -131,6 +131,26 @@ do local _with_0 = "jo" k.j = _with_0 print(_with_0:upper()) + end +end +do + do + local _with_0 = a + print(_with_0.b) + do + local _with_1 = _with_0.c + print(_with_1.d) + end + end +end +do + do + local _with_0 = a + do + local _with_1 = 2 + _with_0.b = _with_1 + print(_with_1.c) + end return _with_0 end end \ No newline at end of file From fb8bfb740c9db2920b0a9b53f8db5cf7e1f0788b Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 26 Sep 2015 17:46:21 -0700 Subject: [PATCH 284/554] new transform.statments module, last_stm function --- moonscript/transform/statements.lua | 50 ++++++++++++++++++++++++++++ moonscript/transform/statements.moon | 30 +++++++++++++++++ moonscript/types.moon | 1 + spec/transform_spec.moon | 48 ++++++++++++++++++++++++++ 4 files changed, 129 insertions(+) create mode 100644 moonscript/transform/statements.lua create mode 100644 moonscript/transform/statements.moon create mode 100644 spec/transform_spec.moon diff --git a/moonscript/transform/statements.lua b/moonscript/transform/statements.lua new file mode 100644 index 00000000..afad5c45 --- /dev/null +++ b/moonscript/transform/statements.lua @@ -0,0 +1,50 @@ +local ntype, mtype +do + local _obj_0 = require("moonscript.types") + ntype, mtype = _obj_0.ntype, _obj_0.mtype +end +local Run +do + local _base_0 = { + call = function(self, state) + return self.fn(state) + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self, fn) + self.fn = fn + self[1] = "run" + end, + __base = _base_0, + __name = "Run" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + Run = _class_0 +end +local last_stm +last_stm = function(stms) + local last_exp_id = 0 + for i = #stms, 1, -1 do + local stm = stms[i] + if stm and mtype(stm) ~= Run then + if ntype(stm) == "group" then + return last_stm(stm[2]) + end + last_exp_id = i + break + end + end + return stms[last_exp_id], last_exp_id, stms +end +return { + last_stm = last_stm, + Run = Run +} diff --git a/moonscript/transform/statements.moon b/moonscript/transform/statements.moon new file mode 100644 index 00000000..bf214a6a --- /dev/null +++ b/moonscript/transform/statements.moon @@ -0,0 +1,30 @@ + +import ntype, mtype from require "moonscript.types" + +-- A Run is a special statement node that lets a function run and mutate the +-- state of the compiler +class Run + new: (@fn) => + @[1] = "run" + + call: (state) => + @.fn state + +-- extract the last statment from an array of statements +-- is group aware +-- returns: the last statement, the index, the table it was fetched from +last_stm = (stms) -> + last_exp_id = 0 + for i = #stms, 1, -1 + stm = stms[i] + if stm and mtype(stm) != Run + if ntype(stm) == "group" + return last_stm stm[2] + + last_exp_id = i + break + + stms[last_exp_id], last_exp_id, stms + +{:last_stm, :Run} + diff --git a/moonscript/types.moon b/moonscript/types.moon index 9b415231..d7bf3c55 100644 --- a/moonscript/types.moon +++ b/moonscript/types.moon @@ -23,6 +23,7 @@ ntype = (node) -> else "value" +-- gets the class of a type if possible mtype = do moon_type = util.moon.type -- lets us check a smart node without throwing an error diff --git a/spec/transform_spec.moon b/spec/transform_spec.moon new file mode 100644 index 00000000..807175fc --- /dev/null +++ b/spec/transform_spec.moon @@ -0,0 +1,48 @@ + +describe "moonscript.transform.statements", -> + describe "last_stm", -> + import last_stm, Run from require "moonscript.transform.statements" + + it "gets last statement from empty list", -> + assert.same nil, (last_stm {}) + + it "gets last statement", -> + stms = { + {"ref", "butt_world"} + {"ref", "hello_world"} + } + + stm, idx, t = last_stm stms + assert stms[2] == stm + assert.same 2, idx + assert stms == t + + it "gets last statement ignoring run", -> + stms = { + {"ref", "butt_world"} + {"ref", "hello_world"} + Run => print "hi" + } + + stm, idx, t = last_stm stms + assert stms[2] == stm + assert.same 2, idx + assert stms == t + + it "gets last from within group", -> + stms = { + {"ref", "butt_world"} + {"group", { + {"ref", "hello_world"} + {"ref", "cool_world"} + }} + } + + last = stms[2][2][2] + + stm, idx, t = last_stm stms + assert stm == last, "should get last" + assert.same 2, idx + assert t == stms[2][2], "should get correct table" + + From c8552b04dc08bcdc1aaba94c1ec4938b573ae6ca Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 26 Sep 2015 17:53:34 -0700 Subject: [PATCH 285/554] transform last stm --- moonscript/transform/statements.lua | 27 ++++++++++++++++++- moonscript/transform/statements.moon | 17 +++++++++++- spec/transform_spec.moon | 39 ++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 2 deletions(-) diff --git a/moonscript/transform/statements.lua b/moonscript/transform/statements.lua index afad5c45..f71aede5 100644 --- a/moonscript/transform/statements.lua +++ b/moonscript/transform/statements.lua @@ -44,7 +44,32 @@ last_stm = function(stms) end return stms[last_exp_id], last_exp_id, stms end +local transform_last_stm +transform_last_stm = function(stms, fn) + local _, last_idx, _stms = last_stm(stms) + if _stms ~= stms then + error("cannot transform last node in group") + end + return (function() + local _accum_0 = { } + local _len_0 = 1 + for i, stm in ipairs(stms) do + if i == last_idx then + _accum_0[_len_0] = { + "transform", + stm, + fn + } + else + _accum_0[_len_0] = stm + end + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() +end return { + Run = Run, last_stm = last_stm, - Run = Run + transform_last_stm = transform_last_stm } diff --git a/moonscript/transform/statements.moon b/moonscript/transform/statements.moon index bf214a6a..0e3baeb7 100644 --- a/moonscript/transform/statements.moon +++ b/moonscript/transform/statements.moon @@ -26,5 +26,20 @@ last_stm = (stms) -> stms[last_exp_id], last_exp_id, stms -{:last_stm, :Run} +-- transform the last stm is a list of stms +-- will puke on group +transform_last_stm = (stms, fn) -> + _, last_idx, _stms = last_stm stms + + if _stms != stms + error "cannot transform last node in group" + + return for i, stm in ipairs stms + if i == last_idx + {"transform", stm, fn} + else + stm + + +{:Run, :last_stm, :transform_last_stm} diff --git a/spec/transform_spec.moon b/spec/transform_spec.moon index 807175fc..682561d7 100644 --- a/spec/transform_spec.moon +++ b/spec/transform_spec.moon @@ -45,4 +45,43 @@ describe "moonscript.transform.statements", -> assert.same 2, idx assert t == stms[2][2], "should get correct table" + describe "transform_last_stm", -> + import transform_last_stm, Run from require "moonscript.transform.statements" + + it "transforms empty stms", -> + before = {} + after = transform_last_stm before, (n) -> {"wrapped", n} + + assert.same before, after + assert before != after + + it "transforms stms", -> + before = { + {"ref", "butt_world"} + {"ref", "hello_world"} + } + + transformer = (n) -> n + after = transform_last_stm before, transformer + + assert.same { + {"ref", "butt_world"} + {"transform", {"ref", "hello_world"}, transformer} + }, after + + it "transforms empty stms ignoring runs", -> + before = { + {"ref", "butt_world"} + {"ref", "hello_world"} + Run => print "hi" + } + + transformer = (n) -> n + after = transform_last_stm before, transformer + + assert.same { + {"ref", "butt_world"} + {"transform", {"ref", "hello_world"}, transformer} + before[3] + }, after From e26fc29784a52b9baedc70348845a7f5932bc1c9 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 26 Sep 2015 18:05:00 -0700 Subject: [PATCH 286/554] compile_system --- Makefile | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a374fb3e..3a4f3dba 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: test local compile watch lint test_safe +.PHONY: test local compile compile_system watch lint test_safe test: busted -p "_spec.moon$$" @@ -18,6 +18,12 @@ compile: lua5.1 bin/moonc -p bin/moon.moon >> bin/moon echo "-- vim: set filetype=lua:" >> bin/moon +compile_system: + moonc moon/ moonscript/ + echo "#!/usr/bin/env lua" > bin/moon + moonc -p bin/moon.moon >> bin/moon + echo "-- vim: set filetype=lua:" >> bin/moon + watch: moonc moon/ moonscript/ && moonc -w moon/ moonscript/ From aeca8864aefcca49a80bcbe09c40d9ee149ba9f8 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 26 Sep 2015 19:07:04 -0700 Subject: [PATCH 287/554] make helper to make sure right moonscript code is tested, add to lang spec --- spec/helpers.moon | 35 ++++++++++++++++++++++++++++++++++- spec/lang_spec.moon | 22 +++++++++++++--------- 2 files changed, 47 insertions(+), 10 deletions(-) diff --git a/spec/helpers.moon b/spec/helpers.moon index c5ddf9f5..1547d808 100644 --- a/spec/helpers.moon +++ b/spec/helpers.moon @@ -6,4 +6,37 @@ unindent = (str) -> return str unless indent (str\gsub("\n#{indent}", "\n")\gsub "%s+$", "") -{ :unindent } +in_dev = false + +-- this will ensure any moonscript modules included come from the local +-- directory +with_dev = (fn) -> + error "already in dev mode" if in_dev + + -- a package loader that only looks in currect directory + import make_loader from require "loadkit" + loader = make_loader "lua", nil, "./?.lua" + + import setup, teardown from require "busted" + + old_require = _G.require + dev_cache = {} + + setup -> + _G.require = (mod) -> + return dev_cache[mod] if dev_cache[mod] + + if mod\match("moonscript%.") or mod == "moonscript" + dev_cache[mod] = assert(loadfile(assert loader mod))! + return dev_cache[mod] + + old_require mod + + if fn + fn! + + teardown -> + _G.require = old_require + in_dev = false + +{ :unindent, :with_dev } diff --git a/spec/lang_spec.moon b/spec/lang_spec.moon index f6612dd8..b0fa1bab 100644 --- a/spec/lang_spec.moon +++ b/spec/lang_spec.moon @@ -1,12 +1,10 @@ lfs = require "lfs" -parse = require "moonscript.parse" -compile = require "moonscript.compile" -util = require "moonscript.util" +import with_dev from require "spec.helpers" pattern = ... -import unpack from util +unpack = table.unpack or unpack options = { in_dir: "spec/inputs", @@ -20,7 +18,7 @@ options = { tool: "git diff --no-index --color" --color-words" filter: (str) -> -- strip the first four lines - table.concat [line for line in *util.split(str, "\n")[5,]], "\n" + table.concat [l for l in *([line for line in str\gmatch("[^\n]+")])[5,]], "\n" } } @@ -81,12 +79,18 @@ input_fname = (base) -> output_fname = (base) -> options.out_dir .. "/" .. base .. options.output_ext +inputs = for file in lfs.dir options.in_dir + with match = file\match options.input_pattern + continue unless match + +table.sort inputs + describe "input tests", -> - inputs = for file in lfs.dir options.in_dir - with match = file\match options.input_pattern - continue unless match + local parse, compile - table.sort inputs + with_dev -> + parse = require "moonscript.parse" + compile = require "moonscript.compile" for name in *inputs input = input_fname name From 6082a86b11f0ee5e1759097cf33847a8202fb041 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 26 Sep 2015 19:31:01 -0700 Subject: [PATCH 288/554] update all specs to make sure they run with dev code --- spec/cmd_spec.moon | 11 ++- spec/error_rewriting_spec.moon | 140 ++++++++++++++++----------------- spec/helpers.moon | 9 ++- spec/moon_spec.moon | 7 +- spec/moonscript_spec.moon | 4 + spec/transform_spec.moon | 10 ++- 6 files changed, 102 insertions(+), 79 deletions(-) diff --git a/spec/cmd_spec.moon b/spec/cmd_spec.moon index 84012e31..5e7b0dce 100644 --- a/spec/cmd_spec.moon +++ b/spec/cmd_spec.moon @@ -1,9 +1,14 @@ -moonc = require "moonscript.cmd.moonc" +import with_dev from require "spec.helpers" -- TODO: add specs for windows equivalents describe "moonc", -> + local moonc + + dev_loaded = with_dev -> + moonc = require "moonscript.cmd.moonc" + same = (fn, a, b)-> assert.same b, fn a @@ -64,7 +69,7 @@ describe "moonc", -> before_each -> dirs = {} package.loaded.lfs = nil - package.loaded["moonscript.cmd.moonc"] = nil + dev_loaded["moonscript.cmd.moonc"] = nil package.loaded.lfs = { mkdir: (dir) -> table.insert dirs, dir @@ -75,7 +80,7 @@ describe "moonc", -> after_each -> package.loaded.lfs = nil - package.loaded["moonscript.cmd.moonc"] = nil + dev_loaded["moonscript.cmd.moonc"] = nil moonc = require "moonscript.cmd.moonc" it "should make directory", -> diff --git a/spec/error_rewriting_spec.moon b/spec/error_rewriting_spec.moon index 9978d1a2..c3616116 100644 --- a/spec/error_rewriting_spec.moon +++ b/spec/error_rewriting_spec.moon @@ -1,71 +1,71 @@ -moonscript = require "moonscript.base" -errors = require "moonscript.errors" -util = require "moonscript.util" - -import unindent from require "spec.helpers" - -get_rewritten_line_no = (fname) -> - fname = "spec/error_inputs/#{fname}.moon" - chunk = moonscript.loadfile fname - - success, err = pcall chunk - error "`#{fname}` is supposed to have runtime error!" if success - - source = tonumber err\match "^.-:(%d+):" - - line_table = assert require("moonscript.line_tables")["@#{fname}"], "missing line table" - errors.reverse_line_number fname, line_table, source, {} - --- TODO: check entire stack trace -describe "error rewriting", -> - tests = { - "first": 24 - "second": 16 - "third": 11 - } - - for name, expected_no in pairs tests - it "should rewrite line number", -> - assert.same get_rewritten_line_no(name), expected_no - -describe "line map", -> - import to_lua from require "moonscript.base" - - it "should create line table", -> - moon_code = unindent [[ - print "hello world" - if something - print "cats" - ]] - - lua_code, posmap = assert to_lua moon_code - -- print util.debug_posmap(posmap, moon_code, lua_code) - assert.same { 7, 29, 42, 27 }, posmap - - it "should create line table for multiline string", -> - moon_code = unindent [[ - print "one" - x = [==[ - one - two - thre - yes - no - ]==] - print "two" - ]] - - lua_code, posmap = assert to_lua moon_code - -- print util.debug_posmap(posmap, moon_code, lua_code) - assert.same {[1]: 7, [2]: 19, [7]: 19, [8]: 63}, posmap - -describe "error reporting", -> - import to_lua from require "moonscript.base" - it "should compile bad code twice", -> - code, err = to_lua "{b=5}" - assert.truthy err - code, err2 = to_lua "{b=5}" - assert.same err, err2 - - +import unindent, with_dev from require "spec.helpers" + +describe "moonscript.errors", -> + local moonscript, errors, util, to_lua + + -- with_dev -> + moonscript = require "moonscript.base" + errors = require "moonscript.errors" + util = require "moonscript.util" + + {:to_lua} = moonscript + + get_rewritten_line_no = (fname) -> + fname = "spec/error_inputs/#{fname}.moon" + chunk = moonscript.loadfile fname + + success, err = pcall chunk + error "`#{fname}` is supposed to have runtime error!" if success + + source = tonumber err\match "^.-:(%d+):" + + line_table = assert require("moonscript.line_tables")["@#{fname}"], "missing line table" + errors.reverse_line_number fname, line_table, source, {} + + describe "error rewriting", -> + tests = { + "first": 24 + "second": 16 + "third": 11 + } + + for name, expected_no in pairs tests + it "should rewrite line number", -> + assert.same get_rewritten_line_no(name), expected_no + + describe "line map", -> + it "should create line table", -> + moon_code = unindent [[ + print "hello world" + if something + print "cats" + ]] + + lua_code, posmap = assert to_lua moon_code + -- print util.debug_posmap(posmap, moon_code, lua_code) + assert.same { 1, 23, 36, 21 }, posmap + + it "should create line table for multiline string", -> + moon_code = unindent [[ + print "one" + x = [==[ + one + two + thre + yes + no + ]==] + print "two" + ]] + + lua_code, posmap = assert to_lua moon_code + -- print util.debug_posmap(posmap, moon_code, lua_code) + assert.same {[1]: 1, [2]: 13, [7]: 13, [8]: 57}, posmap + + describe "error reporting", -> + it "should compile bad code twice", -> + code, err = to_lua "{b=5}" + assert.truthy err + code, err2 = to_lua "{b=5}" + assert.same err, err2 diff --git a/spec/helpers.moon b/spec/helpers.moon index 1547d808..42d578b3 100644 --- a/spec/helpers.moon +++ b/spec/helpers.moon @@ -4,7 +4,7 @@ unindent = (str) -> indent = str\match "^%s+" return str unless indent - (str\gsub("\n#{indent}", "\n")\gsub "%s+$", "") + (str\gsub("\n#{indent}", "\n")\gsub("%s+$", "")\gsub "^%s+", "") in_dev = false @@ -26,7 +26,10 @@ with_dev = (fn) -> _G.require = (mod) -> return dev_cache[mod] if dev_cache[mod] - if mod\match("moonscript%.") or mod == "moonscript" + testable = mod\match("moonscript%.") or mod == "moonscript" or + mod\match("moon%.") or mod == "moon" + + if testable dev_cache[mod] = assert(loadfile(assert loader mod))! return dev_cache[mod] @@ -39,4 +42,6 @@ with_dev = (fn) -> _G.require = old_require in_dev = false + dev_cache + { :unindent, :with_dev } diff --git a/spec/moon_spec.moon b/spec/moon_spec.moon index 145b5ee1..773e53c0 100644 --- a/spec/moon_spec.moon +++ b/spec/moon_spec.moon @@ -1,8 +1,13 @@ -- test moon library -moon = require "moon" +import with_dev from require "spec.helpers" describe "moon", -> + local moon + + with_dev -> + moon = require "moon" + it "should determine correct type", -> class Test diff --git a/spec/moonscript_spec.moon b/spec/moonscript_spec.moon index 8db55585..b7e5271b 100644 --- a/spec/moonscript_spec.moon +++ b/spec/moonscript_spec.moon @@ -1,6 +1,10 @@ -- moonscript module +import with_dev from require "spec.helpers" + describe "moonscript.base", -> + with_dev! + it "should create moonpath", -> path = ";./?.lua;/usr/share/lua/5.1/?.lua;/usr/share/lua/5.1/?/init.lua;/usr/lib/lua/5.1/?.luac;/home/leafo/.luarocks/lua/5.1/?.lua" import create_moonpath from require "moonscript.base" diff --git a/spec/transform_spec.moon b/spec/transform_spec.moon index 682561d7..b4de4047 100644 --- a/spec/transform_spec.moon +++ b/spec/transform_spec.moon @@ -1,8 +1,13 @@ +import with_dev from require "spec.helpers" + describe "moonscript.transform.statements", -> - describe "last_stm", -> - import last_stm, Run from require "moonscript.transform.statements" + local last_stm, transform_last_stm, Run + with_dev -> + { :last_stm, :transform_last_stm, :Run } = require "moonscript.transform.statements" + + describe "last_stm", -> it "gets last statement from empty list", -> assert.same nil, (last_stm {}) @@ -46,7 +51,6 @@ describe "moonscript.transform.statements", -> assert t == stms[2][2], "should get correct table" describe "transform_last_stm", -> - import transform_last_stm, Run from require "moonscript.transform.statements" it "transforms empty stms", -> before = {} From c451418282949035e73f0570b5cd1df0bc1a6348 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 26 Sep 2015 19:42:28 -0700 Subject: [PATCH 289/554] start a spec writing guide --- README.md | 2 ++ spec/README.md | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 spec/README.md diff --git a/README.md b/README.md index 5b2b555c..bf5359ea 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,8 @@ To run tests, execute from the root directory: busted ``` +Writing specs is a bit more complicated. Check out [the spec writing guide](spec/README.md). + ## License (MIT) Copyright (C) 2015 by Leaf Corcoran diff --git a/spec/README.md b/spec/README.md new file mode 100644 index 00000000..67a99a01 --- /dev/null +++ b/spec/README.md @@ -0,0 +1,58 @@ + +# MoonScript Spec guide + +Because MoonScript is written in MoonScript, and MoonScript specs are written +in MoonScript, you need to be aware of which copy of MoonScript is actually +executing the specs. + +A system installed version of MoonScript is recommended to run the specs (and +for development). This means that you'll typically have two versions of +MoonScript available in the load path: + +* The system version +* The version in the current directory + +> A system install is recommended because you'll always want a functioning +> version of MoonScript to compile with in case you break your development +> version. + +When developing you want to make ensure the tests are executing your changes in +the current directory, and not testing the system install. + +Code running in Busted will have the system install take precedence over the +loaded version. That means that if you `require "moonscript.base"` for a test, +you won't get the local copy. + +The `with_dev` spec helper will ensure that any require calls within the spec +that ask for MoonScript modules. `with_dev` calls a setup and teardown that +replaces `_G.require` with a custom version. + +You'll use it like this: + +```moonscript +import with_dev from require "spec.helpers" +describe "moonscript.base", -> + local moonscript + + with_dev! + + it "should load code", -> + -- the local version is loaded + moonscript = require "moonscript" + moonscript.load "print 12" +``` + + +`with_dev`'s require function will load the `.lua` files in the local +directory, not the `moon` ones. You're responsible for compiling them first +before running the tests. + +You might do + +```bash +$ make compile_system; busted +``` + +> `make compile_system` is a makefile task included in the repo that will build +> MoonScript in the current directory with the version installed to the system + From 326e4208cb167af08c57a8e1cb71ed811847202e Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 26 Sep 2015 20:05:52 -0700 Subject: [PATCH 290/554] update spec guide --- spec/README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/spec/README.md b/spec/README.md index 67a99a01..37699484 100644 --- a/spec/README.md +++ b/spec/README.md @@ -1,5 +1,5 @@ -# MoonScript Spec guide +# MoonScript spec guide Because MoonScript is written in MoonScript, and MoonScript specs are written in MoonScript, you need to be aware of which copy of MoonScript is actually @@ -32,8 +32,6 @@ You'll use it like this: ```moonscript import with_dev from require "spec.helpers" describe "moonscript.base", -> - local moonscript - with_dev! it "should load code", -> From 9dbc1d5062b80e6de3e8e6b7ecff01c825df2553 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 26 Sep 2015 20:06:19 -0700 Subject: [PATCH 291/554] misc --- moonscript/base.lua | 4 +--- moonscript/base.moon | 2 +- moonscript/compile.moon | 2 ++ 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/moonscript/base.lua b/moonscript/base.lua index e436678a..6bc0d49e 100644 --- a/moonscript/base.lua +++ b/moonscript/base.lua @@ -66,9 +66,7 @@ end moon_loader = function(name) local name_path = name:gsub("%.", dirsep) local file, file_path - local _list_0 = split(package.moonpath, ";") - for _index_0 = 1, #_list_0 do - local path = _list_0[_index_0] + for path in package.moonpath:gmatch("[^;]+") do file_path = path:gsub("?", name_path) file = io.open(file_path) if file then diff --git a/moonscript/base.moon b/moonscript/base.moon index b2068f0b..3a4502d4 100644 --- a/moonscript/base.moon +++ b/moonscript/base.moon @@ -38,7 +38,7 @@ moon_loader = (name) -> name_path = name\gsub "%.", dirsep local file, file_path - for path in *split package.moonpath, ";" + for path in package.moonpath\gmatch "[^;]+" file_path = path\gsub "?", name_path file = io.open file_path break if file diff --git a/moonscript/compile.moon b/moonscript/compile.moon index d05a3bb7..6206b264 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -406,6 +406,8 @@ class Block nil + -- takes the existing set of lines and replaces them with the result of + -- calling fn on them splice: (fn) => lines = {"lines", @_lines} @_lines = Lines! From ad7be54ff9cface121f02a1fea1b562926b2e64b Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 26 Sep 2015 20:06:41 -0700 Subject: [PATCH 292/554] move some stuff around --- moonscript/transform.lua | 75 ++++++++------------------------------- moonscript/transform.moon | 64 ++++++++++++--------------------- 2 files changed, 36 insertions(+), 103 deletions(-) diff --git a/moonscript/transform.lua b/moonscript/transform.lua index d81a6100..50266e76 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -12,63 +12,16 @@ do local _obj_0 = require("moonscript.transform.names") NameProxy, LocalName = _obj_0.NameProxy, _obj_0.LocalName end +local Run, transform_last_stm +do + local _obj_0 = require("moonscript.transform.statements") + Run, transform_last_stm = _obj_0.Run, _obj_0.transform_last_stm +end local destructure = require("moonscript.transform.destructure") local NOOP = { "noop" } -local Run, apply_to_last, is_singular, extract_declarations, expand_elseif_assign, constructor_name, with_continue_listener, Transformer, construct_comprehension, Statement, Accumulator, default_accumulator, implicitly_return, Value -do - local _base_0 = { - call = function(self, state) - return self.fn(state) - end - } - _base_0.__index = _base_0 - local _class_0 = setmetatable({ - __init = function(self, fn) - self.fn = fn - self[1] = "run" - end, - __base = _base_0, - __name = "Run" - }, { - __index = _base_0, - __call = function(cls, ...) - local _self_0 = setmetatable({}, _base_0) - cls.__init(_self_0, ...) - return _self_0 - end - }) - _base_0.__class = _class_0 - Run = _class_0 -end -apply_to_last = function(stms, fn) - local last_exp_id = 0 - for i = #stms, 1, -1 do - local stm = stms[i] - if stm and mtype(stm) ~= Run then - last_exp_id = i - break - end - end - return (function() - local _accum_0 = { } - local _len_0 = 1 - for i, stm in ipairs(stms) do - if i == last_exp_id then - _accum_0[_len_0] = { - "transform", - stm, - fn - } - else - _accum_0[_len_0] = stm - end - _len_0 = _len_0 + 1 - end - return _accum_0 - end)() -end +local is_singular, extract_declarations, expand_elseif_assign, constructor_name, with_continue_listener, Transformer, construct_comprehension, Statement, Accumulator, default_accumulator, implicitly_return, Value is_singular = function(body) if #body ~= 1 then return false @@ -323,7 +276,7 @@ Statement = Transformer({ return fn(node) end, root_stms = function(self, body) - return apply_to_last(body, implicitly_return(self)) + return transform_last_stm(body, implicitly_return(self)) end, ["return"] = function(self, node) local ret_val = node[2] @@ -338,7 +291,7 @@ Statement = Transformer({ if ret_val_type == "chain" or ret_val_type == "comprehension" or ret_val_type == "tblcomprehension" then ret_val = Value:transform_once(self, ret_val) if ntype(ret_val) == "block_exp" then - return build.group(apply_to_last(ret_val[2], function(stm) + return build.group(transform_last_stm(ret_val[2], function(stm) return { "return", stm @@ -565,7 +518,7 @@ Statement = Transformer({ end, ["do"] = function(self, node, ret) if ret then - node[2] = apply_to_last(node[2], ret) + node[2] = transform_last_stm(node[2], ret) end return node end, @@ -676,11 +629,11 @@ Statement = Transformer({ node = expand_elseif_assign(node) if ret then smart_node(node) - node['then'] = apply_to_last(node['then'], ret) + node['then'] = transform_last_stm(node['then'], ret) for i = 4, #node do local case = node[i] local body_idx = #node[i] - case[body_idx] = apply_to_last(case[body_idx], ret) + case[body_idx] = transform_last_stm(case[body_idx], ret) end end return node @@ -861,7 +814,7 @@ Statement = Transformer({ body = case_exps end if ret then - body = apply_to_last(body, ret) + body = transform_last_stm(body, ret) end insert(out, body) return out @@ -1305,7 +1258,7 @@ do body = { } val = single_stm else - body = apply_to_last(body, function(n) + body = transform_last_stm(body, function(n) if types.is_value(n) then return build.assign_one(self.value_name, n) else @@ -1498,7 +1451,7 @@ Value = Transformer({ end, fndef = function(self, node) smart_node(node) - node.body = apply_to_last(node.body, implicitly_return(self)) + node.body = transform_last_stm(node.body, implicitly_return(self)) node.body = { Run(function(self) return self:listen("varargs", function() end) diff --git a/moonscript/transform.moon b/moonscript/transform.moon index 8b47c2db..18978760 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -6,37 +6,15 @@ data = require "moonscript.data" import reversed, unpack from util import ntype, mtype, build, smart_node, is_slice, value_is_singular from types import insert from table + import NameProxy, LocalName from require "moonscript.transform.names" +import Run, transform_last_stm from require "moonscript.transform.statements" destructure = require "moonscript.transform.destructure" NOOP = {"noop"} local * -class Run - new: (@fn) => - self[1] = "run" - - call: (state) => - self.fn state - --- transform the last stm is a list of stms --- will puke on group -apply_to_last = (stms, fn) -> - -- find last (real) exp - last_exp_id = 0 - for i = #stms, 1, -1 - stm = stms[i] - if stm and mtype(stm) != Run - last_exp_id = i - break - - return for i, stm in ipairs stms - if i == last_exp_id - {"transform", stm, fn} - else - stm - -- is a body a sindle expression/statement is_singular = (body) -> return false if #body != 1 @@ -82,6 +60,7 @@ constructor_name = "new" with_continue_listener = (body) -> continue_name = nil + { Run => @listen "continue", -> @@ -95,16 +74,17 @@ with_continue_listener = (body) -> Run => return unless continue_name @put_name continue_name, nil - @splice (lines) -> { - {"assign", {continue_name}, {"false"}} - {"repeat", "true", { - lines - {"assign", {continue_name}, {"true"}} - }} - {"if", {"not", continue_name}, { - {"break"} - }} - } + @splice (lines) -> + { + {"assign", {continue_name}, {"false"}} + {"repeat", "true", { + lines + {"assign", {continue_name}, {"true"}} + }} + {"if", {"not", continue_name}, { + {"break"} + }} + } } @@ -173,7 +153,7 @@ Statement = Transformer { fn node root_stms: (body) => - apply_to_last body, implicitly_return @ + transform_last_stm body, implicitly_return @ return: (node) => ret_val = node[2] @@ -190,7 +170,7 @@ Statement = Transformer { if ret_val_type == "chain" or ret_val_type == "comprehension" or ret_val_type == "tblcomprehension" ret_val = Value\transform_once @, ret_val if ntype(ret_val) == "block_exp" - return build.group apply_to_last ret_val[2], (stm)-> + return build.group transform_last_stm ret_val[2], (stm)-> {"return", stm} node[2] = ret_val @@ -323,7 +303,7 @@ Statement = Transformer { construct_comprehension action(exp), clauses do: (node, ret) => - node[2] = apply_to_last node[2], ret if ret + node[2] = transform_last_stm node[2], ret if ret node decorated: (node) => @@ -381,11 +361,11 @@ Statement = Transformer { if ret smart_node node -- mutate all the bodies - node['then'] = apply_to_last node['then'], ret + node['then'] = transform_last_stm node['then'], ret for i = 4, #node case = node[i] body_idx = #node[i] - case[body_idx] = apply_to_last case[body_idx], ret + case[body_idx] = transform_last_stm case[body_idx], ret node @@ -519,7 +499,7 @@ Statement = Transformer { body = case_exps if ret - body = apply_to_last body, ret + body = transform_last_stm body, ret insert out, body @@ -786,7 +766,7 @@ class Accumulator body = {} single_stm else - body = apply_to_last body, (n) -> + body = transform_last_stm body, (n) -> if types.is_value n build.assign_one @value_name, n else @@ -905,7 +885,7 @@ Value = Transformer { fndef: (node) => smart_node node - node.body = apply_to_last node.body, implicitly_return self + node.body = transform_last_stm node.body, implicitly_return self node.body = { Run => @listen "varargs", -> -- capture event unpack node.body From 7f423613d726dc3b664799f34f601ea4a89bca4f Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 26 Sep 2015 20:07:12 -0700 Subject: [PATCH 293/554] update rockspec --- moonscript-dev-1.rockspec | 1 + 1 file changed, 1 insertion(+) diff --git a/moonscript-dev-1.rockspec b/moonscript-dev-1.rockspec index 00dd0544..68c82d52 100644 --- a/moonscript-dev-1.rockspec +++ b/moonscript-dev-1.rockspec @@ -44,6 +44,7 @@ build = { ["moonscript.transform"] = "moonscript/transform.lua", ["moonscript.transform.destructure"] = "moonscript/transform/destructure.lua", ["moonscript.transform.names"] = "moonscript/transform/names.lua", + ["moonscript.transform.statements"] = "moonscript/transform/statements.lua", ["moonscript.types"] = "moonscript/types.lua", ["moonscript.util"] = "moonscript/util.lua", ["moonscript.version"] = "moonscript/version.lua", From be0c7d47fcf3f715c77e3d1321cf1b592d6c7450 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 26 Sep 2015 20:12:52 -0700 Subject: [PATCH 294/554] fix travis? --- .travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 55a8e747..14c0f5b5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,8 +3,9 @@ language: c install: - sudo apt-get install luarocks - mkdir -p ~/.luarocks - - echo 'rocks_servers = { "http://rocks.moonscript.org" }' > ~/.luarocks/config.lua - - sudo luarocks install https://rocks.moonscript.org/manifests/olivine-labs/busted-2.0.rc7-0.rockspec + - echo 'rocks_servers = { "http://luarocks.org" }' > ~/.luarocks/config.lua + - sudo luarocks install https://raw.githubusercontent.com/Olivine-Labs/busted/master/busted-2.0.rc10-0.rockspec + - sudo luarocks install https://raw.githubusercontent.com/leafo/loadkit/master/loadkit-dev-1.rockspec - sudo luarocks make script: busted From 70c5c79ed996082310cb0f1547387b025ba34477 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 26 Sep 2015 20:15:36 -0700 Subject: [PATCH 295/554] woop --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 14c0f5b5..e9e6313d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ install: - sudo apt-get install luarocks - mkdir -p ~/.luarocks - echo 'rocks_servers = { "http://luarocks.org" }' > ~/.luarocks/config.lua - - sudo luarocks install https://raw.githubusercontent.com/Olivine-Labs/busted/master/busted-2.0.rc10-0.rockspec + - sudo luarocks install https://luarocks.org/manifests/olivine-labs/busted-2.0.rc7-0.rockspec - sudo luarocks install https://raw.githubusercontent.com/leafo/loadkit/master/loadkit-dev-1.rockspec - sudo luarocks make From 87c88feb280b297b7d1eabb751f4e7c659d2971d Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 26 Sep 2015 20:29:39 -0700 Subject: [PATCH 296/554] make sure return/break at end don't interfere with continue logic fixes #215 #190 #183 --- moonscript/transform.lua | 15 +++++++++++++-- moonscript/transform.moon | 8 +++++++- spec/inputs/loops.moon | 9 +++++++++ spec/outputs/loops.lua | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 61 insertions(+), 3 deletions(-) diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 50266e76..ac548dee 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -12,10 +12,10 @@ do local _obj_0 = require("moonscript.transform.names") NameProxy, LocalName = _obj_0.NameProxy, _obj_0.LocalName end -local Run, transform_last_stm +local Run, transform_last_stm, last_stm do local _obj_0 = require("moonscript.transform.statements") - Run, transform_last_stm = _obj_0.Run, _obj_0.transform_last_stm + Run, transform_last_stm, last_stm = _obj_0.Run, _obj_0.transform_last_stm, _obj_0.last_stm end local destructure = require("moonscript.transform.destructure") local NOOP = { @@ -115,8 +115,19 @@ with_continue_listener = function(body) if not (continue_name) then return end + local last = last_stm(body) + local t = last and ntype(last) + local enclose_lines = t == "return" or t == "break" self:put_name(continue_name, nil) return self:splice(function(lines) + if enclose_lines then + lines = { + "do", + { + lines + } + } + end return { { "assign", diff --git a/moonscript/transform.moon b/moonscript/transform.moon index 18978760..09e1c074 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -8,7 +8,7 @@ import ntype, mtype, build, smart_node, is_slice, value_is_singular from types import insert from table import NameProxy, LocalName from require "moonscript.transform.names" -import Run, transform_last_stm from require "moonscript.transform.statements" +import Run, transform_last_stm, last_stm from require "moonscript.transform.statements" destructure = require "moonscript.transform.destructure" NOOP = {"noop"} @@ -73,8 +73,14 @@ with_continue_listener = (body) -> Run => return unless continue_name + last = last_stm body + t = last and ntype(last) + enclose_lines = t == "return" or t == "break" + @put_name continue_name, nil @splice (lines) -> + lines = {"do", {lines}} if enclose_lines + { {"assign", {continue_name}, {"false"}} {"repeat", "true", { diff --git a/spec/inputs/loops.moon b/spec/inputs/loops.moon index fbdc6380..a704e562 100644 --- a/spec/inputs/loops.moon +++ b/spec/inputs/loops.moon @@ -114,6 +114,15 @@ for x=1,10 for y = 2,12 continue if y % 3 == 0 + +while true + continue if false + break + +while true + continue if false + return 22 + -- do diff --git a/spec/outputs/loops.lua b/spec/outputs/loops.lua index dcba0bc1..db9aef33 100644 --- a/spec/outputs/loops.lua +++ b/spec/outputs/loops.lua @@ -260,6 +260,38 @@ for x = 1, 10 do break end end +while true do + local _continue_0 = false + repeat + do + if false then + _continue_0 = true + break + end + break + end + _continue_0 = true + until true + if not _continue_0 then + break + end +end +while true do + local _continue_0 = false + repeat + do + if false then + _continue_0 = true + break + end + return 22 + end + _continue_0 = true + until true + if not _continue_0 then + break + end +end do local xxx = { 1, From f273598e37a0da211c6a46e22b48e00c7b396154 Mon Sep 17 00:00:00 2001 From: Kyra 'nonchip' Zimmer Date: Tue, 21 Jul 2015 08:52:02 +0200 Subject: [PATCH 297/554] should fix #200 --- moonscript/parse.moon | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/moonscript/parse.moon b/moonscript/parse.moon index 0dd07a02..7b81bb39 100644 --- a/moonscript/parse.moon +++ b/moonscript/parse.moon @@ -260,7 +260,8 @@ build_grammar = wrap_env debug_grammar, (root) -> Invoke: FnArgs/mark"call" + SingleString / wrap_func_arg + - DoubleString / wrap_func_arg + DoubleString / wrap_func_arg + + LuaString / wrap_func_arg TableValue: KeyValue + Ct(Exp) From 36528f1dd019f945269caef0722108ede2f196d6 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 26 Sep 2015 20:59:33 -0700 Subject: [PATCH 298/554] rebuild, specs for new string precedence --- moonscript/parse.lua | 2 +- spec/inputs/syntax.moon | 3 +++ spec/outputs/syntax.lua | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 1ec4f115..d3d8c226 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -171,7 +171,7 @@ local build_grammar = wrap_env(debug_grammar, function(root) Slice = symx("[") * (SliceValue + Cc(1)) * sym(",") * (SliceValue + Cc("")) * (sym(",") * SliceValue) ^ -1 * sym("]") / mark("slice"), ColonCall = symx("\\") * (_Name * Invoke) / mark("colon"), ColonSuffix = symx("\\") * _Name / mark("colon_stub"), - Invoke = FnArgs / mark("call") + SingleString / wrap_func_arg + DoubleString / wrap_func_arg, + Invoke = FnArgs / mark("call") + SingleString / wrap_func_arg + DoubleString / wrap_func_arg + LuaString / wrap_func_arg, TableValue = KeyValue + Ct(Exp), TableLit = sym("{") * Ct(TableValueList ^ -1 * sym(",") ^ -1 * (SpaceBreak * TableLitLine * (sym(",") ^ -1 * SpaceBreak * TableLitLine) ^ 0 * sym(",") ^ -1) ^ -1) * White * sym("}") / mark("table"), TableValueList = TableValue * (sym(",") * TableValue) ^ 0, diff --git a/spec/inputs/syntax.moon b/spec/inputs/syntax.moon index 09a5dabd..a1829a5a 100644 --- a/spec/inputs/syntax.moon +++ b/spec/inputs/syntax.moon @@ -66,6 +66,9 @@ something 'else', "ya" something'else' something"else" +something[[hey]] * 2 +something[======[hey]======] * 2 + here(we)"go"[12123] -- this runs diff --git a/spec/outputs/syntax.lua b/spec/outputs/syntax.lua index 72d3dab6..2ad418d0 100644 --- a/spec/outputs/syntax.lua +++ b/spec/outputs/syntax.lua @@ -53,6 +53,8 @@ end) something('else', "ya") something('else') something("else") +something([[hey]] * 2) +something([======[hey]======] * 2) _ = here(we)("go")[12123] local something = { test = 12323, From 73e9df684184e91d4e010e83ad4bdd98ed73eff8 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 26 Sep 2015 20:59:46 -0700 Subject: [PATCH 299/554] clean out some stuff from makefile --- Makefile | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 3a4f3dba..c4d3c8d0 100644 --- a/Makefile +++ b/Makefile @@ -1,17 +1,11 @@ -.PHONY: test local compile compile_system watch lint test_safe +.PHONY: test local compile compile_system watch lint test: - busted -p "_spec.moon$$" - -test_safe: - busted -p "_spec.lua$$" + busted local: compile luarocks make --local moonscript-dev-1.rockspec -global: - sudo luarocks make moonscript-dev-1.rockspec - compile: lua5.1 bin/moonc moon/ moonscript/ echo "#!/usr/bin/env lua" > bin/moon From 96406947080a38d9897408adcf85c4520a17eb5a Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 26 Sep 2015 21:07:22 -0700 Subject: [PATCH 300/554] rebuild spec --- spec/outputs/syntax.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/outputs/syntax.lua b/spec/outputs/syntax.lua index 2ad418d0..3d2b625b 100644 --- a/spec/outputs/syntax.lua +++ b/spec/outputs/syntax.lua @@ -53,8 +53,8 @@ end) something('else', "ya") something('else') something("else") -something([[hey]] * 2) -something([======[hey]======] * 2) +_ = something([[hey]]) * 2 +_ = something([======[hey]======]) * 2 _ = here(we)("go")[12123] local something = { test = 12323, From ce396acb155632497f1442b40bee111dc75574fe Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 26 Sep 2015 21:16:02 -0700 Subject: [PATCH 301/554] fixes #208 --- moonscript/transform.lua | 24 +++++++++++++++--------- moonscript/transform.moon | 17 ++++++++++------- moonscript/types.lua | 7 ++++++- moonscript/types.moon | 15 +++++++++++---- spec/inputs/with.moon | 5 +++++ spec/outputs/with.lua | 9 ++++++++- 6 files changed, 55 insertions(+), 22 deletions(-) diff --git a/moonscript/transform.lua b/moonscript/transform.lua index ac548dee..8590ec81 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -116,8 +116,7 @@ with_continue_listener = function(body) return end local last = last_stm(body) - local t = last and ntype(last) - local enclose_lines = t == "return" or t == "break" + local enclose_lines = types.terminating[last and ntype(last)] self:put_name(continue_name, nil) return self:splice(function(lines) if enclose_lines then @@ -653,6 +652,14 @@ Statement = Transformer({ local exp, block = unpack(node, 2) local copy_scope = true local scope_name, named_assign + do + local last = last_stm(block) + if last then + if types.terminating[ntype(last)] then + ret = false + end + end + end if ntype(exp) == "assign" then local names, values = unpack(exp, 2) local first_name = names[1] @@ -676,19 +683,18 @@ Statement = Transformer({ copy_scope = false end scope_name = scope_name or NameProxy("with") - return build["do"]({ + local out = build["do"]({ copy_scope and build.assign_one(scope_name, exp) or NOOP, named_assign or NOOP, Run(function(self) return self:set("scope_var", scope_name) end), - build.group(block), - (function() - if ret then - return ret(scope_name) - end - end)() + unpack(block) }) + if ret then + table.insert(out[2], ret(scope_name)) + end + return out end, foreach = function(self, node, _) smart_node(node) diff --git a/moonscript/transform.moon b/moonscript/transform.moon index 09e1c074..4352554c 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -74,8 +74,7 @@ with_continue_listener = (body) -> Run => return unless continue_name last = last_stm body - t = last and ntype(last) - enclose_lines = t == "return" or t == "break" + enclose_lines = types.terminating[last and ntype(last)] @put_name continue_name, nil @splice (lines) -> @@ -381,6 +380,8 @@ Statement = Transformer { copy_scope = true local scope_name, named_assign + if last = last_stm block + ret = false if types.terminating[ntype(last)] if ntype(exp) == "assign" names, values = unpack exp, 2 @@ -403,16 +404,18 @@ Statement = Transformer { scope_name or= NameProxy "with" - build.do { + out = build.do { copy_scope and build.assign_one(scope_name, exp) or NOOP named_assign or NOOP Run => @set "scope_var", scope_name - build.group block - - if ret - ret scope_name + unpack block } + if ret + table.insert out[2], ret scope_name + + out + foreach: (node, _) => smart_node node source = unpack node.iter diff --git a/moonscript/types.lua b/moonscript/types.lua index ccf1d53a..29c24527 100644 --- a/moonscript/types.lua +++ b/moonscript/types.lua @@ -19,6 +19,10 @@ local cascading = Set({ "class", "do" }) +local terminating = Set({ + "return", + "break" +}) local ntype ntype = function(node) local _exp_0 = type(node) @@ -317,5 +321,6 @@ return { value_is_singular = value_is_singular, comprehension_has_value = comprehension_has_value, has_value = has_value, - mtype = mtype + mtype = mtype, + terminating = terminating } diff --git a/moonscript/types.moon b/moonscript/types.moon index d7bf3c55..ad00a1d0 100644 --- a/moonscript/types.moon +++ b/moonscript/types.moon @@ -6,12 +6,20 @@ import insert from table import unpack from util -- implicit return does not work on these statements -manual_return = Set{"foreach", "for", "while", "return"} +manual_return = Set { + "foreach", "for", "while", "return" +} -- Assigns and returns are bubbled into their bodies. -- All cascading statement transform functions accept a second arugment that -- is the transformation to apply to the last statement in their body -cascading = Set{ "if", "unless", "with", "switch", "class", "do" } +cascading = Set { + "if", "unless", "with", "switch", "class", "do" +} + +terminating = Set { + "return", "break" +} -- type of node as string ntype = (node) -> @@ -185,7 +193,6 @@ smart_node = (node) -> { :ntype, :smart_node, :build, :is_value, :is_slice, :manual_return, - :cascading, :value_is_singular, :comprehension_has_value, :has_value, - :mtype + :cascading, :value_is_singular, :comprehension_has_value, :has_value, :mtype, :terminating } diff --git a/spec/inputs/with.moon b/spec/inputs/with.moon index 16f3574d..31ce9b5d 100644 --- a/spec/inputs/with.moon +++ b/spec/inputs/with.moon @@ -106,3 +106,8 @@ do with .b = 2 print .c +do + -> + with hi + return .a, .b + diff --git a/spec/outputs/with.lua b/spec/outputs/with.lua index 62fbb1ca..8fcb7aa5 100644 --- a/spec/outputs/with.lua +++ b/spec/outputs/with.lua @@ -151,6 +151,13 @@ do _with_0.b = _with_1 print(_with_1.c) end - return _with_0 + end +end +do + return function() + do + local _with_0 = hi + return _with_0.a, _with_0.b + end end end \ No newline at end of file From c24acf490bf44216b8bf206b0135e230528ce52e Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 29 Sep 2015 00:32:46 -0700 Subject: [PATCH 302/554] fix regression from #200 --- moonscript/parse.lua | 2 +- moonscript/parse.moon | 2 +- moonscript/parse/util.moon | 2 +- spec/inputs/syntax.moon | 9 +++++++++ spec/outputs/syntax.lua | 6 ++++++ 5 files changed, 18 insertions(+), 3 deletions(-) diff --git a/moonscript/parse.lua b/moonscript/parse.lua index d3d8c226..026734dc 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -171,7 +171,7 @@ local build_grammar = wrap_env(debug_grammar, function(root) Slice = symx("[") * (SliceValue + Cc(1)) * sym(",") * (SliceValue + Cc("")) * (sym(",") * SliceValue) ^ -1 * sym("]") / mark("slice"), ColonCall = symx("\\") * (_Name * Invoke) / mark("colon"), ColonSuffix = symx("\\") * _Name / mark("colon_stub"), - Invoke = FnArgs / mark("call") + SingleString / wrap_func_arg + DoubleString / wrap_func_arg + LuaString / wrap_func_arg, + Invoke = FnArgs / mark("call") + SingleString / wrap_func_arg + DoubleString / wrap_func_arg + #P("[") * LuaString / wrap_func_arg, TableValue = KeyValue + Ct(Exp), TableLit = sym("{") * Ct(TableValueList ^ -1 * sym(",") ^ -1 * (SpaceBreak * TableLitLine * (sym(",") ^ -1 * SpaceBreak * TableLitLine) ^ 0 * sym(",") ^ -1) ^ -1) * White * sym("}") / mark("table"), TableValueList = TableValue * (sym(",") * TableValue) ^ 0, diff --git a/moonscript/parse.moon b/moonscript/parse.moon index 7b81bb39..a2245808 100644 --- a/moonscript/parse.moon +++ b/moonscript/parse.moon @@ -261,7 +261,7 @@ build_grammar = wrap_env debug_grammar, (root) -> Invoke: FnArgs/mark"call" + SingleString / wrap_func_arg + DoubleString / wrap_func_arg + - LuaString / wrap_func_arg + #P"[" * LuaString / wrap_func_arg TableValue: KeyValue + Ct(Exp) diff --git a/moonscript/parse/util.moon b/moonscript/parse/util.moon index fc680d7f..e12e1f84 100644 --- a/moonscript/parse/util.moon +++ b/moonscript/parse/util.moon @@ -109,7 +109,7 @@ format_single_assign = (lhs, assign) -> -- a symbol sym = (chars) -> Space * chars --- a symbole that doesn't accept whitespace before it +-- a symbol that doesn't accept whitespace before it symx = (chars) -> chars -- a constructor for quote delimited strings diff --git a/spec/inputs/syntax.moon b/spec/inputs/syntax.moon index a1829a5a..05ce0671 100644 --- a/spec/inputs/syntax.moon +++ b/spec/inputs/syntax.moon @@ -69,6 +69,15 @@ something"else" something[[hey]] * 2 something[======[hey]======] * 2 + +something'else', 2 +something"else", 2 +something[[else]], 2 + +something 'else', 2 +something "else", 2 +something [[else]], 2 + here(we)"go"[12123] -- this runs diff --git a/spec/outputs/syntax.lua b/spec/outputs/syntax.lua index 3d2b625b..f19a3e69 100644 --- a/spec/outputs/syntax.lua +++ b/spec/outputs/syntax.lua @@ -55,6 +55,12 @@ something('else') something("else") _ = something([[hey]]) * 2 _ = something([======[hey]======]) * 2 +_ = something('else'), 2 +_ = something("else"), 2 +_ = something([[else]]), 2 +something('else', 2) +something("else", 2) +something([[else]], 2) _ = here(we)("go")[12123] local something = { test = 12323, From b9efd31af7fb5cf520e7352dde83aaa5900b3e3b Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 30 Sep 2015 00:57:08 -0700 Subject: [PATCH 303/554] add another super test --- spec/inputs/class.moon | 1 + spec/outputs/class.lua | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/spec/inputs/class.moon b/spec/inputs/class.moon index 1d27e5e5..ebcca20e 100644 --- a/spec/inputs/class.moon +++ b/spec/inputs/class.moon @@ -77,6 +77,7 @@ class CoolSuper super\yeah"world".okay hi, hi, hi something.super super.super.super.super + super\hello nil diff --git a/spec/outputs/class.lua b/spec/outputs/class.lua index 35c7153d..b16ba179 100644 --- a/spec/outputs/class.lua +++ b/spec/outputs/class.lua @@ -319,6 +319,13 @@ do _parent_0.yeah(self, "world").okay(hi, hi, hi) _ = something.super _ = _parent_0.super.super.super + do + local _base_1 = _parent_0 + local _fn_0 = _base_1.hello + _ = function(...) + return _fn_0(self, ...) + end + end return nil end } From 8db100691658ac60c95fc473dda56494c6f6b69e Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 27 Sep 2015 00:39:31 -0700 Subject: [PATCH 304/554] start simplifying chain ast --- moonscript/compile/value.lua | 2 +- moonscript/compile/value.moon | 2 +- moonscript/parse.lua | 21 ++++++-------- moonscript/parse.moon | 41 ++++++++++------------------ moonscript/parse/util.lua | 16 ++++------- moonscript/parse/util.moon | 18 ++++-------- moonscript/transform.lua | 12 ++++---- moonscript/transform.moon | 11 +++----- moonscript/transform/statements.lua | 8 +++++- moonscript/transform/statements.moon | 5 +++- 10 files changed, 58 insertions(+), 78 deletions(-) diff --git a/moonscript/compile/value.lua b/moonscript/compile/value.lua index 8f8e8f23..07220247 100644 --- a/moonscript/compile/value.lua +++ b/moonscript/compile/value.lua @@ -95,7 +95,7 @@ return { elseif t == "dot" then return ".", tostring(arg) elseif t == "colon" then - return ":", arg, chain_item(node[3]) + return ":", tostring(arg) elseif t == "colon_stub" then return user_error("Uncalled colon stub") else diff --git a/moonscript/compile/value.moon b/moonscript/compile/value.moon index 515fed87..c8f9891b 100644 --- a/moonscript/compile/value.moon +++ b/moonscript/compile/value.moon @@ -64,7 +64,7 @@ string_chars = { elseif t == "dot" ".", tostring arg elseif t == "colon" - ":", arg, chain_item(node[3]) + ":", tostring arg elseif t == "colon_stub" user_error "Uncalled colon stub" else diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 026734dc..13fb8aa8 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -27,10 +27,10 @@ Num = Space * (Num / function(v) v } end) -local Indent, Cut, ensure, extract_line, mark, pos, flatten_or_mark, is_assignable, check_assignable, format_assign, format_single_assign, sym, symx, simple_string, wrap_func_arg, flatten_func, flatten_string_chain, wrap_decorator, check_lua_string, self_assign +local Indent, Cut, ensure, extract_line, mark, pos, flatten_or_mark, is_assignable, check_assignable, format_assign, format_single_assign, sym, symx, simple_string, wrap_func_arg, join_chain, flatten_string_chain, wrap_decorator, check_lua_string, self_assign do local _obj_0 = require("moonscript.parse.util") - Indent, Cut, ensure, extract_line, mark, pos, flatten_or_mark, is_assignable, check_assignable, format_assign, format_single_assign, sym, symx, simple_string, wrap_func_arg, flatten_func, flatten_string_chain, wrap_decorator, check_lua_string, self_assign = _obj_0.Indent, _obj_0.Cut, _obj_0.ensure, _obj_0.extract_line, _obj_0.mark, _obj_0.pos, _obj_0.flatten_or_mark, _obj_0.is_assignable, _obj_0.check_assignable, _obj_0.format_assign, _obj_0.format_single_assign, _obj_0.sym, _obj_0.symx, _obj_0.simple_string, _obj_0.wrap_func_arg, _obj_0.flatten_func, _obj_0.flatten_string_chain, _obj_0.wrap_decorator, _obj_0.check_lua_string, _obj_0.self_assign + Indent, Cut, ensure, extract_line, mark, pos, flatten_or_mark, is_assignable, check_assignable, format_assign, format_single_assign, sym, symx, simple_string, wrap_func_arg, join_chain, flatten_string_chain, wrap_decorator, check_lua_string, self_assign = _obj_0.Indent, _obj_0.Cut, _obj_0.ensure, _obj_0.extract_line, _obj_0.mark, _obj_0.pos, _obj_0.flatten_or_mark, _obj_0.is_assignable, _obj_0.check_assignable, _obj_0.format_assign, _obj_0.format_single_assign, _obj_0.sym, _obj_0.symx, _obj_0.simple_string, _obj_0.wrap_func_arg, _obj_0.join_chain, _obj_0.flatten_string_chain, _obj_0.wrap_decorator, _obj_0.check_lua_string, _obj_0.self_assign end local build_grammar = wrap_env(debug_grammar, function(root) local _indent = Stack(0) @@ -148,13 +148,12 @@ local build_grammar = wrap_env(debug_grammar, function(root) CharOperators = Space * C(S("+-*/%^><")), WordOperators = op("or") + op("and") + op("<=") + op(">=") + op("~=") + op("!=") + op("==") + op(".."), BinaryOperator = (WordOperators + CharOperators) * SpaceBreak ^ 0, - Assignable = Cmt(DotChain + Chain, check_assignable) + Name + SelfName, + Assignable = Cmt(Chain, check_assignable) + Name + SelfName, Exp = Ct(Value * (BinaryOperator * Value) ^ 0) / flatten_or_mark("exp"), SimpleValue = If + Unless + Switch + With + ClassDecl + ForEach + For + While + Cmt(Do, check_do) + sym("-") * -SomeSpace * Exp / mark("minus") + sym("#") * Exp / mark("length") + key("not") * Exp / mark("not") + TblComprehension + TableLit + Comprehension + FunLit + Num, - ChainValue = StringChain + ((Chain + DotChain + Callable) * Ct(InvokeArgs ^ -1)) / flatten_func, - Value = pos(SimpleValue + Ct(KeyValueList) / mark("table") + ChainValue), + ChainValue = (Chain + Callable) * Ct(InvokeArgs ^ -1) / join_chain, + Value = pos(SimpleValue + Ct(KeyValueList) / mark("table") + ChainValue + String), SliceValue = SimpleValue + ChainValue, - StringChain = String * (Ct((ColonCall + ColonSuffix) * ChainTail ^ -1) * Ct(InvokeArgs ^ -1)) ^ -1 / flatten_string_chain, String = Space * DoubleString + Space * SingleString + LuaString, SingleString = simple_string("'"), DoubleString = simple_string('"', true), @@ -164,13 +163,11 @@ local build_grammar = wrap_env(debug_grammar, function(root) Callable = pos(Name / mark("ref")) + SelfName + VarArg + Parens / mark("parens"), Parens = sym("(") * SpaceBreak ^ 0 * Exp * SpaceBreak ^ 0 * sym(")"), FnArgs = symx("(") * SpaceBreak ^ 0 * Ct(ExpList ^ -1) * SpaceBreak ^ 0 * sym(")") + sym("!") * -P("=") * Ct(""), - ChainTail = ChainItem ^ 1 * ColonSuffix ^ -1 + ColonSuffix, - Chain = Callable * ChainTail / mark("chain"), - DotChain = (sym(".") * Cc(-1) * (_Name / mark("dot")) * ChainTail ^ -1) / mark("chain") + (sym("\\") * Cc(-1) * ((_Name * Invoke / mark("colon")) * ChainTail ^ -1 + (_Name / mark("colon_stub")))) / mark("chain"), - ChainItem = Invoke + Slice + symx("[") * Exp / mark("index") * sym("]") + symx(".") * _Name / mark("dot") + ColonCall, + Chain = (Callable + String + -S(".\\")) * ChainItems / mark("chain"), + ChainItems = ChainItem ^ 1 * ColonChainItem ^ -1 + ColonChainItem, + ChainItem = Invoke + symx(".") * _Name / mark("dot") + Slice + symx("[") * Exp / mark("index") * sym("]"), + ColonChainItem = symx("\\") * _Name / mark("colon") * (Invoke * ChainItems ^ -1) ^ -1, Slice = symx("[") * (SliceValue + Cc(1)) * sym(",") * (SliceValue + Cc("")) * (sym(",") * SliceValue) ^ -1 * sym("]") / mark("slice"), - ColonCall = symx("\\") * (_Name * Invoke) / mark("colon"), - ColonSuffix = symx("\\") * _Name / mark("colon_stub"), Invoke = FnArgs / mark("call") + SingleString / wrap_func_arg + DoubleString / wrap_func_arg + #P("[") * LuaString / wrap_func_arg, TableValue = KeyValue + Ct(Exp), TableLit = sym("{") * Ct(TableValueList ^ -1 * sym(",") ^ -1 * (SpaceBreak * TableLitLine * (sym(",") ^ -1 * SpaceBreak * TableLitLine) ^ 0 * sym(",") ^ -1) ^ -1) * White * sym("}") / mark("table"), diff --git a/moonscript/parse.moon b/moonscript/parse.moon index a2245808..dac6b813 100644 --- a/moonscript/parse.moon +++ b/moonscript/parse.moon @@ -3,6 +3,7 @@ lpeg = require "lpeg" lpeg.setmaxstack 10000 -- whoa + err_msg = "Failed to parse:%s\n [%d] >> %s" import Stack from require "moonscript.data" @@ -27,7 +28,7 @@ Num = Space * (Num / (v) -> {"number", v}) { :Indent, :Cut, :ensure, :extract_line, :mark, :pos, :flatten_or_mark, :is_assignable, :check_assignable, :format_assign, :format_single_assign, - :sym, :symx, :simple_string, :wrap_func_arg, :flatten_func, + :sym, :symx, :simple_string, :wrap_func_arg, :join_chain, :flatten_string_chain, :wrap_decorator, :check_lua_string, :self_assign } = require "moonscript.parse.util" @@ -183,7 +184,7 @@ build_grammar = wrap_env debug_grammar, (root) -> WordOperators: op"or" + op"and" + op"<=" + op">=" + op"~=" + op"!=" + op"==" + op".." BinaryOperator: (WordOperators + CharOperators) * SpaceBreak^0 - Assignable: Cmt(DotChain + Chain, check_assignable) + Name + SelfName + Assignable: Cmt(Chain, check_assignable) + Name + SelfName Exp: Ct(Value * (BinaryOperator * Value)^0) / flatten_or_mark"exp" SimpleValue: @@ -202,20 +203,17 @@ build_grammar = wrap_env debug_grammar, (root) -> FunLit + Num - ChainValue: -- a function call or an object access - StringChain + - ((Chain + DotChain + Callable) * Ct(InvokeArgs^-1)) / flatten_func + -- a function call or an object access + ChainValue: (Chain + Callable) * Ct(InvokeArgs^-1) / join_chain Value: pos( SimpleValue + Ct(KeyValueList) / mark"table" + - ChainValue) + ChainValue + + String) SliceValue: SimpleValue + ChainValue - StringChain: String * - (Ct((ColonCall + ColonSuffix) * ChainTail^-1) * Ct(InvokeArgs^-1))^-1 / flatten_string_chain - String: Space * DoubleString + Space * SingleString + LuaString SingleString: simple_string("'") DoubleString: simple_string('"', true) @@ -232,33 +230,23 @@ build_grammar = wrap_env debug_grammar, (root) -> FnArgs: symx"(" * SpaceBreak^0 * Ct(ExpList^-1) * SpaceBreak^0 * sym")" + sym"!" * -P"=" * Ct"" - ChainTail: ChainItem^1 * ColonSuffix^-1 + ColonSuffix - -- a list of funcalls and indexes on a callable - Chain: Callable * ChainTail / mark"chain" + Chain: (Callable + String + -S".\\") * ChainItems / mark"chain" - -- shorthand dot call for use in with statement - DotChain: - (sym"." * Cc(-1) * (_Name / mark"dot") * ChainTail^-1) / mark"chain" + - (sym"\\" * Cc(-1) * ( - (_Name * Invoke / mark"colon") * ChainTail^-1 + - (_Name / mark"colon_stub") - )) / mark"chain" + ChainItems: ChainItem^1 * ColonChainItem^-1 + ColonChainItem ChainItem: Invoke + - Slice + - symx"[" * Exp/mark"index" * sym"]" + symx"." * _Name/mark"dot" + - ColonCall + Slice + + symx"[" * Exp/mark"index" * sym"]" + + ColonChainItem: symx"\\" * _Name / mark"colon" * (Invoke * ChainItems^-1)^-1 Slice: symx"[" * (SliceValue + Cc(1)) * sym"," * (SliceValue + Cc"") * (sym"," * SliceValue)^-1 *sym"]" / mark"slice" - ColonCall: symx"\\" * (_Name * Invoke) / mark"colon" - ColonSuffix: symx"\\" * _Name / mark"colon_stub" - - Invoke: FnArgs/mark"call" + + Invoke: FnArgs / mark"call" + SingleString / wrap_func_arg + DoubleString / wrap_func_arg + #P"[" * LuaString / wrap_func_arg @@ -314,6 +302,7 @@ build_grammar = wrap_env debug_grammar, (root) -> ExpList: Exp * (sym"," * Exp)^0 ExpListLow: Exp * ((sym"," + sym";") * Exp)^0 + -- open args InvokeArgs: -P"-" * (ExpList * (sym"," * (TableBlock + SpaceBreak * Advance * ArgBlock * TableBlock^-1) + TableBlock)^-1 + TableBlock) ArgBlock: ArgLine * (sym"," * SpaceBreak * ArgLine)^0 * PopIndent ArgLine: CheckIndent * ExpList diff --git a/moonscript/parse/util.lua b/moonscript/parse/util.lua index 6db63f06..a93665dc 100644 --- a/moonscript/parse/util.lua +++ b/moonscript/parse/util.lua @@ -178,8 +178,8 @@ wrap_func_arg = function(value) } } end -local flatten_func -flatten_func = function(callee, args) +local join_chain +join_chain = function(callee, args) if #args == 0 then return callee end @@ -188,13 +188,7 @@ flatten_func = function(callee, args) args } if ntype(callee) == "chain" then - local stub = callee[#callee] - if ntype(stub) == "colon_stub" then - stub[1] = "colon" - table.insert(stub, args) - else - table.insert(callee, args) - end + table.insert(callee, args) return callee end return { @@ -208,7 +202,7 @@ flatten_string_chain = function(str, chain, args) if not (chain) then return str end - return flatten_func({ + return flatten_chain({ "chain", str, unpack(chain) @@ -259,7 +253,7 @@ return { symx = symx, simple_string = simple_string, wrap_func_arg = wrap_func_arg, - flatten_func = flatten_func, + join_chain = join_chain, flatten_string_chain = flatten_string_chain, wrap_decorator = wrap_decorator, check_lua_string = check_lua_string, diff --git a/moonscript/parse/util.moon b/moonscript/parse/util.moon index e12e1f84..2039e3bd 100644 --- a/moonscript/parse/util.moon +++ b/moonscript/parse/util.moon @@ -127,27 +127,21 @@ simple_string = (delim, allow_interpolation) -> -- wraps a single value in format needed to be passed as function arguments wrap_func_arg = (value) -> {"call", {value}} --- flatten out the parsed function node -flatten_func = (callee, args) -> +-- chains are parsed in two captures, the chain and then the open arguments +-- if there are open arguments, then append them to the end of the chain as a call +join_chain = (callee, args) -> return callee if #args == 0 args = {"call", args} if ntype(callee) == "chain" - -- check for colon stub needing arguments - stub = callee[#callee] - if ntype(stub) == "colon_stub" - stub[1] = "colon" - table.insert stub, args - else - table.insert callee, args - + table.insert callee, args return callee {"chain", callee, args} flatten_string_chain = (str, chain, args) -> return str unless chain - flatten_func {"chain", str, unpack chain}, args + flatten_chain {"chain", str, unpack chain}, args -- constructor for decorator node wrap_decorator = (stm, dec) -> @@ -163,5 +157,5 @@ self_assign = (name, pos) -> { :Indent, :Cut, :ensure, :extract_line, :mark, :pos, :flatten_or_mark, :is_assignable, :check_assignable, :format_assign, :format_single_assign, - :sym, :symx, :simple_string, :wrap_func_arg, :flatten_func, + :sym, :symx, :simple_string, :wrap_func_arg, :join_chain, :flatten_string_chain, :wrap_decorator, :check_lua_string, :self_assign } diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 8590ec81..0b1e1d0b 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -12,10 +12,10 @@ do local _obj_0 = require("moonscript.transform.names") NameProxy, LocalName = _obj_0.NameProxy, _obj_0.LocalName end -local Run, transform_last_stm, last_stm +local Run, transform_last_stm, last_stm, chain_is_stub do local _obj_0 = require("moonscript.transform.statements") - Run, transform_last_stm, last_stm = _obj_0.Run, _obj_0.transform_last_stm, _obj_0.last_stm + Run, transform_last_stm, last_stm, chain_is_stub = _obj_0.Run, _obj_0.transform_last_stm, _obj_0.last_stm, _obj_0.chain_is_stub end local destructure = require("moonscript.transform.destructure") local NOOP = { @@ -1498,7 +1498,6 @@ Value = Transformer({ }) end, chain = function(self, node) - local stub = node[#node] for i = 3, #node do local part = node[i] if ntype(part) == "dot" and data.lua_keywords[part[2]] then @@ -1517,10 +1516,11 @@ Value = Transformer({ "parens", node[2] } - elseif type(stub) == "table" and stub[1] == "colon_stub" then - table.remove(node, #node) + end + if chain_is_stub(node) then local base_name = NameProxy("base") local fn_name = NameProxy("fn") + local colon = table.remove(node) local is_super = ntype(node[2]) == "ref" and node[2][2] == "super" return build.block_exp({ build.assign({ @@ -1540,7 +1540,7 @@ Value = Transformer({ base = base_name, { "dot", - stub[2] + colon[2] } }) } diff --git a/moonscript/transform.moon b/moonscript/transform.moon index 4352554c..9be3292c 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -8,7 +8,7 @@ import ntype, mtype, build, smart_node, is_slice, value_is_singular from types import insert from table import NameProxy, LocalName from require "moonscript.transform.names" -import Run, transform_last_stm, last_stm from require "moonscript.transform.statements" +import Run, transform_last_stm, last_stm, chain_is_stub from require "moonscript.transform.statements" destructure = require "moonscript.transform.destructure" NOOP = {"noop"} @@ -910,8 +910,6 @@ Value = Transformer { -- pull out colon chain chain: (node) => - stub = node[#node] - -- escape lua keywords used in dot accessors for i=3,#node part = node[i] @@ -921,12 +919,11 @@ Value = Transformer { if ntype(node[2]) == "string" -- add parens if callee is raw string node[2] = {"parens", node[2] } - elseif type(stub) == "table" and stub[1] == "colon_stub" - -- convert colon stub into code - table.remove node, #node + if chain_is_stub node base_name = NameProxy "base" fn_name = NameProxy "fn" + colon = table.remove node is_super = ntype(node[2]) == "ref" and node[2][2] == "super" build.block_exp { @@ -938,7 +935,7 @@ Value = Transformer { build.assign { names: {fn_name} values: { - build.chain { base: base_name, {"dot", stub[2]} } + build.chain { base: base_name, {"dot", colon[2]} } } } diff --git a/moonscript/transform/statements.lua b/moonscript/transform/statements.lua index f71aede5..169590ea 100644 --- a/moonscript/transform/statements.lua +++ b/moonscript/transform/statements.lua @@ -68,8 +68,14 @@ transform_last_stm = function(stms, fn) return _accum_0 end)() end +local chain_is_stub +chain_is_stub = function(chain) + local stub = chain[#chain] + return stub and ntype(stub) == "colon" +end return { Run = Run, last_stm = last_stm, - transform_last_stm = transform_last_stm + transform_last_stm = transform_last_stm, + chain_is_stub = chain_is_stub } diff --git a/moonscript/transform/statements.moon b/moonscript/transform/statements.moon index 0e3baeb7..59d8e364 100644 --- a/moonscript/transform/statements.moon +++ b/moonscript/transform/statements.moon @@ -40,6 +40,9 @@ transform_last_stm = (stms, fn) -> else stm +chain_is_stub = (chain) -> + stub = chain[#chain] + stub and ntype(stub) == "colon" -{:Run, :last_stm, :transform_last_stm} +{:Run, :last_stm, :transform_last_stm, :chain_is_stub} From 6a057b6b5605f5965ebdc511d648840206ce9015 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 29 Sep 2015 02:17:40 -0700 Subject: [PATCH 305/554] show preview of buffer on non-terminal debugger --- moonscript/parse/env.lua | 5 +++-- moonscript/parse/env.moon | 6 ++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/moonscript/parse/env.lua b/moonscript/parse/env.lua index 6dbed84a..f805211b 100644 --- a/moonscript/parse/env.lua +++ b/moonscript/parse/env.lua @@ -34,8 +34,9 @@ wrap_env = function(debug, fn) end wrap_name = function(name) local v = V(name) - v = Cmt("", function() - iprint("* " .. name) + v = Cmt("", function(str, pos) + local rest = str:sub(pos, -1):match("^([^\n]*)") + iprint("* " .. tostring(name) .. " (" .. tostring(rest) .. ")") indent = indent + 1 return true end) * Cmt(v, function(str, pos, ...) diff --git a/moonscript/parse/env.moon b/moonscript/parse/env.moon index 25dcc1e4..ea71c3df 100644 --- a/moonscript/parse/env.moon +++ b/moonscript/parse/env.moon @@ -18,8 +18,10 @@ wrap_env = (debug, fn) -> wrap_name = (name) -> v = V name - v = Cmt("", -> - iprint "* " .. name + v = Cmt("", (str, pos) -> + rest = str\sub(pos, -1)\match "^([^\n]*)" + + iprint "* #{name} (#{rest})" indent += 1 true ) * Cmt(v, (str, pos, ...) -> From e94494721a2c63050ca44546845e719855c8caba Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 29 Sep 2015 02:18:58 -0700 Subject: [PATCH 306/554] bring back dot/colon prefix chain --- moonscript/compile/value.lua | 8 +++++--- moonscript/compile/value.moon | 9 ++++++--- moonscript/parse.lua | 10 ++++++---- moonscript/parse.moon | 12 +++++++----- 4 files changed, 24 insertions(+), 15 deletions(-) diff --git a/moonscript/compile/value.lua b/moonscript/compile/value.lua index 07220247..3641cc9d 100644 --- a/moonscript/compile/value.lua +++ b/moonscript/compile/value.lua @@ -71,11 +71,13 @@ return { chain = function(self, node) local callee = node[2] local callee_type = ntype(callee) - if callee == -1 then + local item_offset = 3 + if callee_type == "dot" or callee_type == "colon" then callee = self:get("scope_var") - if not callee then + if not (callee) then user_error("Short-dot syntax must be called within a with block") end + item_offset = 2 end if callee_type == "ref" and callee[2] == "super" or callee == "super" then do @@ -112,7 +114,7 @@ return { local actions do local _with_0 = self:line() - for _index_0 = 3, #node do + for _index_0 = item_offset, #node do local action = node[_index_0] _with_0:append(chain_item(action)) end diff --git a/moonscript/compile/value.moon b/moonscript/compile/value.moon index c8f9891b..bbe0d230 100644 --- a/moonscript/compile/value.moon +++ b/moonscript/compile/value.moon @@ -44,10 +44,13 @@ string_chars = { chain: (node) => callee = node[2] callee_type = ntype callee + item_offset = 3 - if callee == -1 + if callee_type == "dot" or callee_type == "colon" callee = @get "scope_var" - if not callee then user_error "Short-dot syntax must be called within a with block" + unless callee + user_error "Short-dot syntax must be called within a with block" + item_offset = 2 -- TODO: don't use string literals as ref if callee_type == "ref" and callee[2] == "super" or callee == "super" @@ -77,7 +80,7 @@ string_chars = { callee_value = @line "(", callee_value, ")" if ntype(callee) == "exp" actions = with @line! - \append chain_item action for action in *node[3,] + \append chain_item action for action in *node[item_offset,] @line callee_value, actions diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 13fb8aa8..30846db7 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -163,10 +163,12 @@ local build_grammar = wrap_env(debug_grammar, function(root) Callable = pos(Name / mark("ref")) + SelfName + VarArg + Parens / mark("parens"), Parens = sym("(") * SpaceBreak ^ 0 * Exp * SpaceBreak ^ 0 * sym(")"), FnArgs = symx("(") * SpaceBreak ^ 0 * Ct(ExpList ^ -1) * SpaceBreak ^ 0 * sym(")") + sym("!") * -P("=") * Ct(""), - Chain = (Callable + String + -S(".\\")) * ChainItems / mark("chain"), - ChainItems = ChainItem ^ 1 * ColonChainItem ^ -1 + ColonChainItem, - ChainItem = Invoke + symx(".") * _Name / mark("dot") + Slice + symx("[") * Exp / mark("index") * sym("]"), - ColonChainItem = symx("\\") * _Name / mark("colon") * (Invoke * ChainItems ^ -1) ^ -1, + Chain = (Callable + String + -S(".\\")) * ChainItems / mark("chain") + Space * (DotChainItem * ChainItems ^ -1 + ColonChain) / mark("chain"), + ChainItems = ChainItem ^ 1 * ColonChain ^ -1 + ColonChain, + ChainItem = Invoke + DotChainItem + Slice + symx("[") * Exp / mark("index") * sym("]"), + DotChainItem = symx(".") * _Name / mark("dot"), + ColonChainItem = symx("\\") * _Name / mark("colon"), + ColonChain = ColonChainItem * (Invoke * ChainItems ^ -1) ^ -1, Slice = symx("[") * (SliceValue + Cc(1)) * sym(",") * (SliceValue + Cc("")) * (sym(",") * SliceValue) ^ -1 * sym("]") / mark("slice"), Invoke = FnArgs / mark("call") + SingleString / wrap_func_arg + DoubleString / wrap_func_arg + #P("[") * LuaString / wrap_func_arg, TableValue = KeyValue + Ct(Exp), diff --git a/moonscript/parse.moon b/moonscript/parse.moon index dac6b813..ca275570 100644 --- a/moonscript/parse.moon +++ b/moonscript/parse.moon @@ -230,18 +230,20 @@ build_grammar = wrap_env debug_grammar, (root) -> FnArgs: symx"(" * SpaceBreak^0 * Ct(ExpList^-1) * SpaceBreak^0 * sym")" + sym"!" * -P"=" * Ct"" - -- a list of funcalls and indexes on a callable - Chain: (Callable + String + -S".\\") * ChainItems / mark"chain" + Chain: (Callable + String + -S".\\") * ChainItems / mark"chain" + + Space * (DotChainItem * ChainItems^-1 + ColonChain) / mark"chain" - ChainItems: ChainItem^1 * ColonChainItem^-1 + ColonChainItem + ChainItems: ChainItem^1 * ColonChain^-1 + ColonChain ChainItem: Invoke + - symx"." * _Name/mark"dot" + + DotChainItem + Slice + symx"[" * Exp/mark"index" * sym"]" - ColonChainItem: symx"\\" * _Name / mark"colon" * (Invoke * ChainItems^-1)^-1 + DotChainItem: symx"." * _Name/mark"dot" + ColonChainItem: symx"\\" * _Name / mark"colon" + ColonChain: ColonChainItem * (Invoke * ChainItems^-1)^-1 Slice: symx"[" * (SliceValue + Cc(1)) * sym"," * (SliceValue + Cc"") * (sym"," * SliceValue)^-1 *sym"]" / mark"slice" From 02a20ea69545307865a0c273449d072569042119 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 29 Sep 2015 20:47:27 -0700 Subject: [PATCH 307/554] add some specs for name extract --- moonscript/transform/destructure.lua | 3 +- moonscript/transform/destructure.moon | 2 +- spec/transform_spec.moon | 49 +++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/moonscript/transform/destructure.lua b/moonscript/transform/destructure.lua index c0542953..6798c611 100644 --- a/moonscript/transform/destructure.lua +++ b/moonscript/transform/destructure.lua @@ -228,5 +228,6 @@ end return { has_destructure = has_destructure, split_assign = split_assign, - build_assign = build_assign + build_assign = build_assign, + extract_assign_names = extract_assign_names } diff --git a/moonscript/transform/destructure.moon b/moonscript/transform/destructure.moon index ca80bc25..eef2852e 100644 --- a/moonscript/transform/destructure.moon +++ b/moonscript/transform/destructure.moon @@ -123,4 +123,4 @@ split_assign = (scope, assign) -> build.group g -{ :has_destructure, :split_assign, :build_assign } +{ :has_destructure, :split_assign, :build_assign, :extract_assign_names } diff --git a/spec/transform_spec.moon b/spec/transform_spec.moon index b4de4047..dba44d04 100644 --- a/spec/transform_spec.moon +++ b/spec/transform_spec.moon @@ -1,6 +1,55 @@ import with_dev from require "spec.helpers" +describe "moonscript.transform.destructure", -> + local extract_assign_names + + with_dev -> + { :extract_assign_names } = require "moonscript.transform.destructure" + + it "extracts names from table destructure", -> + des = { + "table" + { + {{"key_literal", "hi"}, {"ref", "hi"}} + {{"key_literal", "world"}, {"ref", "world"}} + } + } + + assert.same { + { + {"ref", "hi"} -- target + { + {"dot", "hi"} + } -- chain suffix + } + + { + {"ref", "world"} + { + {"dot", "world"} + } + } + + }, extract_assign_names des + + it "extracts names from array destructure", -> + des = { + "table" + { + {{"ref", "hi"}} + } + } + + assert.same { + { + {"ref", "hi"} + { + {"index", {"number", 1}} + } + } + }, extract_assign_names des + describe "moonscript.transform.statements", -> local last_stm, transform_last_stm, Run From 2f71fbc13f18d1c2c6628aa6470b9adaa8da72e4 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 29 Sep 2015 21:06:51 -0700 Subject: [PATCH 308/554] use colon instead of colon stub for bound import --- moonscript/parse.lua | 2 +- moonscript/parse.moon | 2 +- moonscript/transform.lua | 10 +++++----- moonscript/transform.moon | 4 ++-- moonscript/transform/destructure.lua | 2 +- moonscript/transform/destructure.moon | 4 +++- 6 files changed, 13 insertions(+), 11 deletions(-) diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 30846db7..53c12f05 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -120,7 +120,7 @@ local build_grammar = wrap_env(debug_grammar, function(root) InBlock = Advance * Block * PopIndent, Local = key("local") * ((op("*") + op("^")) / mark("declare_glob") + Ct(NameList) / mark("declare_with_shadows")), Import = key("import") * Ct(ImportNameList) * SpaceBreak ^ 0 * key("from") * Exp / mark("import"), - ImportName = (sym("\\") * Ct(Cc("colon_stub") * Name) + Name), + ImportName = (sym("\\") * Ct(Cc("colon") * Name) + Name), ImportNameList = SpaceBreak ^ 0 * ImportName * ((SpaceBreak ^ 1 + sym(",") * SpaceBreak ^ 0) * ImportName) ^ 0, BreakLoop = Ct(key("break") / trim) + Ct(key("continue") / trim), Return = key("return") * (ExpListLow / mark("explist") + C("")) / mark("return"), diff --git a/moonscript/parse.moon b/moonscript/parse.moon index ca275570..96c26e5f 100644 --- a/moonscript/parse.moon +++ b/moonscript/parse.moon @@ -134,7 +134,7 @@ build_grammar = wrap_env debug_grammar, (root) -> Local: key"local" * ((op"*" + op"^") / mark"declare_glob" + Ct(NameList) / mark"declare_with_shadows") Import: key"import" * Ct(ImportNameList) * SpaceBreak^0 * key"from" * Exp / mark"import" - ImportName: (sym"\\" * Ct(Cc"colon_stub" * Name) + Name) + ImportName: (sym"\\" * Ct(Cc"colon" * Name) + Name) ImportNameList: SpaceBreak^0 * ImportName * ((SpaceBreak^1 + sym"," * SpaceBreak^0) * ImportName)^0 BreakLoop: Ct(key"break"/trim) + Ct(key"continue"/trim) diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 0b1e1d0b..a378674d 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -484,18 +484,18 @@ Statement = Transformer({ local _len_0 = 1 for _index_0 = 1, #names do local name = names[_index_0] - local dest_val - if ntype(name) == "colon_stub" then - dest_val = name[2] + local dest_name + if ntype(name) == "colon" then + dest_name = name[2] else - dest_val = name + dest_name = name end local _value_0 = { { "key_literal", name }, - dest_val + dest_name } _accum_0[_len_0] = _value_0 _len_0 = _len_0 + 1 diff --git a/moonscript/transform.moon b/moonscript/transform.moon index 9be3292c..accc1530 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -291,12 +291,12 @@ Statement = Transformer { import: (node) => _, names, source = unpack node table_values = for name in *names - dest_val = if ntype(name) == "colon_stub" + dest_name = if ntype(name) == "colon" name[2] else name - {{"key_literal", name}, dest_val} + {{"key_literal", name}, dest_name} dest = { "table", table_values } { "assign", {dest}, {source}, [-1]: node[-1] } diff --git a/moonscript/transform/destructure.lua b/moonscript/transform/destructure.lua index 6798c611..2ec46bef 100644 --- a/moonscript/transform/destructure.lua +++ b/moonscript/transform/destructure.lua @@ -68,7 +68,7 @@ extract_assign_names = function(name, accum, prefix) local s if ntype(key) == "key_literal" then local key_name = key[2] - if ntype(key_name) == "colon_stub" then + if ntype(key_name) == "colon" then s = key_name else s = { diff --git a/moonscript/transform/destructure.moon b/moonscript/transform/destructure.moon index eef2852e..5b22247a 100644 --- a/moonscript/transform/destructure.moon +++ b/moonscript/transform/destructure.moon @@ -20,6 +20,7 @@ has_destructure = (names) -> false extract_assign_names = (name, accum={}, prefix={}) -> + i = 1 for tuple in *name[2] value, suffix = if #tuple == 1 @@ -28,9 +29,10 @@ extract_assign_names = (name, accum={}, prefix={}) -> tuple[1], s else key = tuple[1] + s = if ntype(key) == "key_literal" key_name = key[2] - if ntype(key_name) == "colon_stub" + if ntype(key_name) == "colon" key_name else {"dot", key_name} From e4c4e8e0eead566dacbb40b99cc876b30c90d804 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 30 Sep 2015 01:05:20 -0700 Subject: [PATCH 309/554] update super for new chain ast --- moonscript/transform.lua | 46 +++++++++++++++++---------------------- moonscript/transform.moon | 28 +++++++++++++++++------- 2 files changed, 40 insertions(+), 34 deletions(-) diff --git a/moonscript/transform.lua b/moonscript/transform.lua index a378674d..7ff298b8 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -1099,29 +1099,21 @@ Statement = Transformer({ end return self:set("super", function(block, chain) if chain then - local slice - do - local _accum_0 = { } - local _len_0 = 1 - for _index_0 = 3, #chain do - local item = chain[_index_0] - _accum_0[_len_0] = item - _len_0 = _len_0 + 1 - end - slice = _accum_0 - end + local chain_tail = { + unpack(chain, 3) + } local new_chain = { "chain", parent_cls_name } - local head = slice[1] + local head = chain_tail[1] if head == nil then return parent_cls_name end local _exp_1 = head[1] if "call" == _exp_1 then local calling_name = block:get("current_block") - slice[1] = { + chain_tail[1] = { "call", { "self", @@ -1140,21 +1132,23 @@ Statement = Transformer({ }) end elseif "colon" == _exp_1 then - local call = head[3] - insert(new_chain, { - "dot", - head[2] - }) - slice[1] = { - "call", - { - "self", - unpack(call[2]) + local call = chain_tail[2] + if call and call[1] == "call" then + chain_tail[1] = { + "dot", + head[2] } - } + chain_tail[2] = { + "call", + { + "self", + unpack(call[2]) + } + } + end end - for _index_0 = 1, #slice do - local item = slice[_index_0] + for _index_0 = 1, #chain_tail do + local item = chain_tail[_index_0] insert(new_chain, item) end return new_chain diff --git a/moonscript/transform.moon b/moonscript/transform.moon index accc1530..528a5189 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -661,10 +661,10 @@ Statement = Transformer { @set "super", (block, chain) -> if chain - slice = [item for item in *chain[3,]] + chain_tail = { unpack chain, 3 } new_chain = {"chain", parent_cls_name} - head = slice[1] + head = chain_tail[1] if head == nil return parent_cls_name @@ -673,7 +673,7 @@ Statement = Transformer { -- calling super, inject calling name and self into chain when "call" calling_name = block\get"current_block" - slice[1] = {"call", {"self", unpack head[2]}} + chain_tail[1] = {"call", {"self", unpack head[2]}} if ntype(calling_name) == "key_literal" insert new_chain, {"dot", calling_name[2]} @@ -682,11 +682,23 @@ Statement = Transformer { -- colon call on super, replace class with self as first arg when "colon" - call = head[3] - insert new_chain, {"dot", head[2]} - slice[1] = { "call", { "self", unpack call[2] } } - - insert new_chain, item for item in *slice + call = chain_tail[2] + -- calling chain tail + if call and call[1] == "call" + chain_tail[1] = { + "dot" + head[2] + } + + chain_tail[2] = { + "call" + { + "self" + unpack call[2] + } + } + + insert new_chain, item for item in *chain_tail new_chain else From c4ad47c1123c303eeec1ebd3e00973f2297b6da8 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Mon, 5 Oct 2015 20:19:36 -0700 Subject: [PATCH 310/554] replace has_value with functional value_can_be_statement --- moonscript/compile.lua | 10 +++++----- moonscript/compile.moon | 10 +++++----- moonscript/types.lua | 14 ++++++-------- moonscript/types.moon | 15 +++++++-------- 4 files changed, 23 insertions(+), 26 deletions(-) diff --git a/moonscript/compile.lua b/moonscript/compile.lua index 5eab8e6b..98045ce2 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -8,10 +8,10 @@ do end local Set Set = require("moonscript.data").Set -local ntype, has_value +local ntype, value_can_be_statement do local _obj_0 = require("moonscript.types") - ntype, has_value = _obj_0.ntype, _obj_0.has_value + ntype, value_can_be_statement = _obj_0.ntype, _obj_0.value_can_be_statement end local statement_compilers = require("moonscript.compile.statement") local value_compilers = require("moonscript.compile.value") @@ -525,7 +525,9 @@ do if fn then result = fn(self, node, ...) else - if has_value(node) then + if value_can_be_statement(node) then + result = self:value(node) + else result = self:stm({ "assign", { @@ -535,8 +537,6 @@ do node } }) - else - result = self:value(node) end end end diff --git a/moonscript/compile.moon b/moonscript/compile.moon index 6206b264..a2b17fee 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -5,7 +5,7 @@ transform = require "moonscript.transform" import NameProxy, LocalName from require "moonscript.transform.names" import Set from require "moonscript.data" -import ntype, has_value from require "moonscript.types" +import ntype, value_can_be_statement from require "moonscript.types" statement_compilers = require "moonscript.compile.statement" value_compilers = require "moonscript.compile.value" @@ -379,11 +379,11 @@ class Block result = if fn = @statement_compilers[ntype(node)] fn @, node, ... else - -- coerce value into statement - if has_value node - @stm {"assign", {"_"}, {node}} - else + if value_can_be_statement node @value node + else + -- coerce value into statement + @stm {"assign", {"_"}, {node}} if result if type(node) == "table" and type(result) == "table" and node[-1] diff --git a/moonscript/types.lua b/moonscript/types.lua index 29c24527..a8bd6c70 100644 --- a/moonscript/types.lua +++ b/moonscript/types.lua @@ -45,14 +45,12 @@ do return moon_type(val) end end -local has_value -has_value = function(node) - if ntype(node) == "chain" then - local ctype = ntype(node[#node]) - return ctype ~= "call" and ctype ~= "colon" - else - return true +local value_can_be_statement +value_can_be_statement = function(node) + if not (ntype(node) == "chain") then + return false end + return ntype(node[#node]) == "call" end local is_value is_value = function(stm) @@ -320,7 +318,7 @@ return { cascading = cascading, value_is_singular = value_is_singular, comprehension_has_value = comprehension_has_value, - has_value = has_value, + value_can_be_statement = value_can_be_statement, mtype = mtype, terminating = terminating } diff --git a/moonscript/types.moon b/moonscript/types.moon index ad00a1d0..abac3110 100644 --- a/moonscript/types.moon +++ b/moonscript/types.moon @@ -40,13 +40,11 @@ mtype = do return "table" if mt and mt.smart_node moon_type val --- does this always return a value -has_value = (node) -> - if ntype(node) == "chain" - ctype = ntype(node[#node]) - ctype != "call" and ctype != "colon" - else - true +-- can this value be compiled in a line by itself +value_can_be_statement = (node) -> + return false unless ntype(node) == "chain" + -- it's a function call + ntype(node[#node]) == "call" is_value = (stm) -> compile = require "moonscript.compile" @@ -193,6 +191,7 @@ smart_node = (node) -> { :ntype, :smart_node, :build, :is_value, :is_slice, :manual_return, - :cascading, :value_is_singular, :comprehension_has_value, :has_value, :mtype, :terminating + :cascading, :value_is_singular, :comprehension_has_value, + :value_can_be_statement, :mtype, :terminating } From 24b3a86c68c505ec31040e6c8529bd1e0e8b690e Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Mon, 5 Oct 2015 20:53:54 -0700 Subject: [PATCH 311/554] correct escape new chain format for lua keywords --- moonscript/compile/value.lua | 2 +- moonscript/compile/value.moon | 2 +- moonscript/transform.lua | 2 +- moonscript/transform.moon | 2 +- spec/inputs/with.moon | 5 +++++ spec/outputs/with.lua | 11 ++++++++++- 6 files changed, 19 insertions(+), 5 deletions(-) diff --git a/moonscript/compile/value.lua b/moonscript/compile/value.lua index 3641cc9d..82cc7304 100644 --- a/moonscript/compile/value.lua +++ b/moonscript/compile/value.lua @@ -72,7 +72,7 @@ return { local callee = node[2] local callee_type = ntype(callee) local item_offset = 3 - if callee_type == "dot" or callee_type == "colon" then + if callee_type == "dot" or callee_type == "colon" or callee_type == "index" then callee = self:get("scope_var") if not (callee) then user_error("Short-dot syntax must be called within a with block") diff --git a/moonscript/compile/value.moon b/moonscript/compile/value.moon index bbe0d230..fb5c2253 100644 --- a/moonscript/compile/value.moon +++ b/moonscript/compile/value.moon @@ -46,7 +46,7 @@ string_chars = { callee_type = ntype callee item_offset = 3 - if callee_type == "dot" or callee_type == "colon" + if callee_type == "dot" or callee_type == "colon" or callee_type == "index" callee = @get "scope_var" unless callee user_error "Short-dot syntax must be called within a with block" diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 7ff298b8..7a2d18d4 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -1492,7 +1492,7 @@ Value = Transformer({ }) end, chain = function(self, node) - for i = 3, #node do + for i = 2, #node do local part = node[i] if ntype(part) == "dot" and data.lua_keywords[part[2]] then node[i] = { diff --git a/moonscript/transform.moon b/moonscript/transform.moon index 528a5189..4ad3b66c 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -923,7 +923,7 @@ Value = Transformer { -- pull out colon chain chain: (node) => -- escape lua keywords used in dot accessors - for i=3,#node + for i=2,#node part = node[i] if ntype(part) == "dot" and data.lua_keywords[part[2]] node[i] = { "index", {"string", '"', part[2]} } diff --git a/spec/inputs/with.moon b/spec/inputs/with.moon index 31ce9b5d..ae3c8c05 100644 --- a/spec/inputs/with.moon +++ b/spec/inputs/with.moon @@ -111,3 +111,8 @@ do with hi return .a, .b + +do + with dad + .if "yes" + y = .end.of.function diff --git a/spec/outputs/with.lua b/spec/outputs/with.lua index 8fcb7aa5..3b2eec3b 100644 --- a/spec/outputs/with.lua +++ b/spec/outputs/with.lua @@ -154,10 +154,19 @@ do end end do - return function() + local _ + _ = function() do local _with_0 = hi return _with_0.a, _with_0.b end end +end +do + do + local _with_0 = dad + _with_0["if"]("yes") + local y = _with_0["end"].of["function"] + return _with_0 + end end \ No newline at end of file From 11f0b022c49cc0cd7e1b0e44c98153042dcac9b0 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 19 Nov 2015 18:01:22 -0800 Subject: [PATCH 312/554] use relative reference to parent class instead of closure --- moonscript/compile.lua | 7 ++-- moonscript/transform.moon | 35 ++++++++++++++++--- spec/class_spec.moon | 71 ++++++++++++++++++++++++++++++++++++--- 3 files changed, 102 insertions(+), 11 deletions(-) diff --git a/moonscript/compile.lua b/moonscript/compile.lua index 98045ce2..dad4b79a 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -638,7 +638,7 @@ do __init = function(self, options) self.options = options self.root = self - return _parent_0.__init(self) + return self.__class.__parent.__init(self) end, __base = _base_0, __name = "RootBlock", @@ -647,7 +647,10 @@ do __index = function(cls, name) local val = rawget(_base_0, name) if val == nil then - return _parent_0[name] + local parent = rawget(cls, "__parent") + if parent then + return parent[name] + end else return val end diff --git a/moonscript/transform.moon b/moonscript/transform.moon index 4ad3b66c..5db3b5d6 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -612,7 +612,25 @@ Statement = Transformer { class_lookup = build["if"] { cond: { "exp", {"ref", "val"}, "==", "nil" } then: { - parent_cls_name\index"name" + build.assign_one LocalName"parent", build.chain { + base: "rawget" + { + "call", { + {"ref", "cls"} + {"string", '"', "__parent"} + } + } + } + + build.if { + cond: LocalName "parent" + then: { + build.chain { + base: LocalName "parent" + {"index", "name"} + } + } + } } } insert class_lookup, {"else", {"val"}} @@ -660,14 +678,21 @@ Statement = Transformer { @put_name name if name @set "super", (block, chain) -> + relative_parent = { + "chain", + "self" + {"dot", "__class"} + {"dot", "__parent"} + } + if chain chain_tail = { unpack chain, 3 } - new_chain = {"chain", parent_cls_name} - head = chain_tail[1] if head == nil - return parent_cls_name + return relative_parent + + new_chain = relative_parent switch head[1] -- calling super, inject calling name and self into chain @@ -702,7 +727,7 @@ Statement = Transformer { new_chain else - parent_cls_name + relative_parent {"declare_glob", "*"} diff --git a/spec/class_spec.moon b/spec/class_spec.moon index c46b4415..7b1dbd6e 100644 --- a/spec/class_spec.moon +++ b/spec/class_spec.moon @@ -19,8 +19,7 @@ describe "class", -> instance = Thing! assert.same instance\get_color!, "blue" - - it "should have class property", -> + it "should have base properies from class", -> class Thing color: "blue" get_color: => @color @@ -54,7 +53,6 @@ describe "class", -> assert.same instance.property, "name" assert.same instance.name, "the_thing" - it "should call super method", -> class Base _count: 111 @@ -66,6 +64,18 @@ describe "class", -> instance = Thing! assert.same instance\counter!, "00000111" + it "should call other method from super", -> + class Base + _count: 111 + counter: => + @_count + + class Thing extends Base + other_method: => super\counter! + + instance = Thing! + assert.same instance\other_method!, 111 + it "should get super class", -> class Base class Thing extends Base @@ -102,7 +112,6 @@ describe "class", -> Thing = class assert.same Thing.__name, "Thing" - it "should not expose class properties on instance", -> class Thing @height: 10 @@ -135,3 +144,57 @@ describe "class", -> instance = Thing! instance\go! + it "should have class properies take precedence over base properties", -> + class Thing + @prop: "hello" + prop: "world" + + assert.same "hello", Thing.prop + + it "class properties take precedence in super class over base", -> + class Thing + @prop: "hello" + prop: "world" + + class OtherThing extends Thing + + assert.same "hello", OtherThing.prop + + it "gets value from base in super class", -> + class Thing + prop: "world" + + class OtherThing extends Thing + assert.same "world", OtherThing.prop + + it "should let parent be replaced on class", -> + class A + @prop: "yeah" + cool: => 1234 + plain: => "a" + + class B + @prop: "okay" + cool: => 9999 + plain: => "b" + + class Thing extends A + cool: => + super! + 1 + + get_super: => + super + + instance = Thing! + + assert.same "a", instance\plain! + assert.same 1235, instance\cool! + assert A == instance\get_super!, "expected super to be B" + + Thing.__parent = B + setmetatable Thing.__base, B.__base + + assert.same "b", instance\plain! + assert.same 10000, instance\cool! + assert B == instance\get_super!, "expected super to be B" + From 6aea71f16c772844cc1c92d431c6e4a1bc19b80e Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 19 Nov 2015 18:15:05 -0800 Subject: [PATCH 313/554] rebuild --- moonscript/cmd/lint.lua | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/moonscript/cmd/lint.lua b/moonscript/cmd/lint.lua index 52dba4e0..3a109a3d 100644 --- a/moonscript/cmd/lint.lua +++ b/moonscript/cmd/lint.lua @@ -120,11 +120,11 @@ do end, render = function(self, ...) self:lint_check_unused() - return _parent_0.render(self, ...) + return self.__class.__parent.render(self, ...) end, block = function(self, ...) do - local _with_0 = _parent_0.block(self, ...) + local _with_0 = self.__class.__parent.block(self, ...) _with_0.block = self.block _with_0.render = self.render _with_0.get_root_block = self.get_root_block @@ -143,7 +143,7 @@ do if whitelist_globals == nil then whitelist_globals = default_whitelist end - _parent_0.__init(self, ...) + self.__class.__parent.__init(self, ...) self.get_root_block = function() return self end @@ -206,7 +206,10 @@ do __index = function(cls, name) local val = rawget(_base_0, name) if val == nil then - return _parent_0[name] + local parent = rawget(cls, "__parent") + if parent then + return parent[name] + end else return val end From b4c802fadfe438e1b86d6893ae3c8f141bc6154b Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 19 Nov 2015 18:15:51 -0800 Subject: [PATCH 314/554] rebuild tests for new compiled syntax --- spec/outputs/class.lua | 71 +++++++++++++++++++++++++++--------------- 1 file changed, 46 insertions(+), 25 deletions(-) diff --git a/spec/outputs/class.lua b/spec/outputs/class.lua index b16ba179..b9e6c41c 100644 --- a/spec/outputs/class.lua +++ b/spec/outputs/class.lua @@ -70,7 +70,10 @@ do __index = function(cls, name) local val = rawget(_base_0, name) if val == nil then - return _parent_0[name] + local parent = rawget(cls, "__parent") + if parent then + return parent[name] + end else return val end @@ -118,14 +121,14 @@ do local _parent_0 = Hi local _base_0 = { cool = function(self) - return _parent_0.cool(self, 120302) + return self.__class.__parent.cool(self, 120302) end } _base_0.__index = _base_0 setmetatable(_base_0, _parent_0.__base) local _class_0 = setmetatable({ __init = function(self) - return _parent_0.__init(self, "man") + return self.__class.__parent.__init(self, "man") end, __base = _base_0, __name = "Simple", @@ -134,7 +137,10 @@ do __index = function(cls, name) local val = rawget(_base_0, name) if val == nil then - return _parent_0[name] + local parent = rawget(cls, "__parent") + if parent then + return parent[name] + end else return val end @@ -180,16 +186,16 @@ do local _parent_0 = Okay local _base_0 = { something = function(self) - _parent_0.something(self, 1, 2, 3, 4) - _parent_0.something(another_self, 1, 2, 3, 4) - return assert(_parent_0 == Okay) + self.__class.__parent.something(self, 1, 2, 3, 4) + self.__class.__parent.something(another_self, 1, 2, 3, 4) + return assert(self.__class.__parent == Okay) end } _base_0.__index = _base_0 setmetatable(_base_0, _parent_0.__base) local _class_0 = setmetatable({ __init = function(self, ...) - return _parent_0.__init(self, ...) + return self.__class.__parent.__init(self, ...) end, __base = _base_0, __name = "Biggie", @@ -198,7 +204,10 @@ do __index = function(cls, name) local val = rawget(_base_0, name) if val == nil then - return _parent_0[name] + local parent = rawget(cls, "__parent") + if parent then + return parent[name] + end else return val end @@ -219,7 +228,7 @@ local Yeah do local _base_0 = { okay = function(self) - return _parent_0.something(self, 1, 2, 3, 4) + return self.__class.__parent.something(self, 1, 2, 3, 4) end } _base_0.__index = _base_0 @@ -266,7 +275,7 @@ do local _base_0 = { val = 2323, something = function(self) - local _base_1 = _parent_0 + local _base_1 = self.__class.__parent local _fn_0 = _base_1.something return function(...) return _fn_0(self, ...) @@ -277,7 +286,7 @@ do setmetatable(_base_0, _parent_0.__base) local _class_0 = setmetatable({ __init = function(self, ...) - return _parent_0.__init(self, ...) + return self.__class.__parent.__init(self, ...) end, __base = _base_0, __name = "Hello", @@ -286,7 +295,10 @@ do __index = function(cls, name) local val = rawget(_base_0, name) if val == nil then - return _parent_0[name] + local parent = rawget(cls, "__parent") + if parent then + return parent[name] + end else return val end @@ -313,14 +325,14 @@ local CoolSuper do local _base_0 = { hi = function(self) - _parent_0.hi(self, 1, 2, 3, 4)(1, 2, 3, 4) - _parent_0.something(1, 2, 3, 4) - local _ = _parent_0.something(1, 2, 3, 4).world - _parent_0.yeah(self, "world").okay(hi, hi, hi) + self.__class.__parent.hi(self, 1, 2, 3, 4)(1, 2, 3, 4) + self.__class.__parent.something(1, 2, 3, 4) + local _ = self.__class.__parent.something(1, 2, 3, 4).world + self.__class.__parent.yeah(self, "world").okay(hi, hi, hi) _ = something.super - _ = _parent_0.super.super.super + _ = self.__class.__parent.super.super.super do - local _base_1 = _parent_0 + local _base_1 = self.__class.__parent local _fn_0 = _base_1.hello _ = function(...) return _fn_0(self, ...) @@ -492,7 +504,7 @@ do setmetatable(_base_0, _parent_0.__base) local _class_0 = setmetatable({ __init = function(self, ...) - return _parent_0.__init(self, ...) + return self.__class.__parent.__init(self, ...) end, __base = _base_0, __name = "Something", @@ -501,7 +513,10 @@ do __index = function(cls, name) local val = rawget(_base_0, name) if val == nil then - return _parent_0[name] + local parent = rawget(cls, "__parent") + if parent then + return parent[name] + end else return val end @@ -570,7 +585,7 @@ do setmetatable(_base_0, _parent_0.__base) local _class_0 = setmetatable({ __init = function(self, ...) - return _parent_0.__init(self, ...) + return self.__class.__parent.__init(self, ...) end, __base = _base_0, __name = "Something", @@ -579,7 +594,10 @@ do __index = function(cls, name) local val = rawget(_base_0, name) if val == nil then - return _parent_0[name] + local parent = rawget(cls, "__parent") + if parent then + return parent[name] + end else return val end @@ -605,7 +623,7 @@ do setmetatable(_base_0, _parent_0.__base) local _class_0 = setmetatable({ __init = function(self, ...) - return _parent_0.__init(self, ...) + return self.__class.__parent.__init(self, ...) end, __base = _base_0, __name = "d", @@ -614,7 +632,10 @@ do __index = function(cls, name) local val = rawget(_base_0, name) if val == nil then - return _parent_0[name] + local parent = rawget(cls, "__parent") + if parent then + return parent[name] + end else return val end From 40b7ed61350d9e28518ec5dccce337b5bd673447 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 19 Nov 2015 22:01:48 -0800 Subject: [PATCH 315/554] specs for repeated supers --- spec/class_spec.moon | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/spec/class_spec.moon b/spec/class_spec.moon index 7b1dbd6e..d21e8bff 100644 --- a/spec/class_spec.moon +++ b/spec/class_spec.moon @@ -198,3 +198,39 @@ describe "class", -> assert.same 10000, instance\cool! assert B == instance\get_super!, "expected super to be B" + it "should resolve many levels of super", -> + class One + a: => + 1 + + class Two extends One + a: => + super! + 2 + + class Three extends Two + a: => + super! + 3 + + i = Three! + + assert.same 6, i\a! + + + it "should resolve many levels of super with a gap", -> + class One + a: => + 1 + + class Two extends One + + class Three extends Two + a: => + super! + 3 + + class Four extends Three + a: => + super! + 4 + + i = Four! + + assert.same 8, i\a! From 66d80ed217eca5e18f78cc064fdb3da3a23ceb3a Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 19 Nov 2015 22:02:19 -0800 Subject: [PATCH 316/554] use cls_name for super access, rebuild --- moonscript/cmd/coverage.lua | 3 ++- moonscript/cmd/lint.lua | 9 +++++---- moonscript/compile.lua | 17 +++++++++++------ moonscript/data.lua | 3 ++- moonscript/transform.moon | 4 ++-- moonscript/transform/names.lua | 6 ++++-- moonscript/transform/statements.lua | 3 ++- 7 files changed, 28 insertions(+), 17 deletions(-) diff --git a/moonscript/cmd/coverage.lua b/moonscript/cmd/coverage.lua index 8c585e83..4fd36806 100644 --- a/moonscript/cmd/coverage.lua +++ b/moonscript/cmd/coverage.lua @@ -58,6 +58,7 @@ format_file = function(fname, positions) end local CodeCoverage do + local _class_0 local _base_0 = { reset = function(self) self.line_counts = create_counter() @@ -120,7 +121,7 @@ do end } _base_0.__index = _base_0 - local _class_0 = setmetatable({ + _class_0 = setmetatable({ __init = function(self) return self:reset() end, diff --git a/moonscript/cmd/lint.lua b/moonscript/cmd/lint.lua index 3a109a3d..50509e57 100644 --- a/moonscript/cmd/lint.lua +++ b/moonscript/cmd/lint.lua @@ -52,6 +52,7 @@ local default_whitelist = Set({ }) local LinterBlock do + local _class_0 local _parent_0 = Block local _base_0 = { lint_mark_used = function(self, name) @@ -120,11 +121,11 @@ do end, render = function(self, ...) self:lint_check_unused() - return self.__class.__parent.render(self, ...) + return _class_0.__parent.render(self, ...) end, block = function(self, ...) do - local _with_0 = self.__class.__parent.block(self, ...) + local _with_0 = _class_0.__parent.block(self, ...) _with_0.block = self.block _with_0.render = self.render _with_0.get_root_block = self.get_root_block @@ -138,12 +139,12 @@ do } _base_0.__index = _base_0 setmetatable(_base_0, _parent_0.__base) - local _class_0 = setmetatable({ + _class_0 = setmetatable({ __init = function(self, whitelist_globals, ...) if whitelist_globals == nil then whitelist_globals = default_whitelist end - self.__class.__parent.__init(self, ...) + _class_0.__parent.__init(self, ...) self.get_root_block = function() return self end diff --git a/moonscript/compile.lua b/moonscript/compile.lua index dad4b79a..0715b862 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -26,6 +26,7 @@ local mtype = util.moon.type local indent_char = " " local Line, DelayedLine, Lines, Block, RootBlock do + local _class_0 local _base_0 = { mark_pos = function(self, pos, line) if line == nil then @@ -127,7 +128,7 @@ do end } _base_0.__index = _base_0 - local _class_0 = setmetatable({ + _class_0 = setmetatable({ __init = function(self) self.posmap = { } end, @@ -145,6 +146,7 @@ do Lines = _class_0 end do + local _class_0 local _base_0 = { pos = nil, append_list = function(self, items, delim) @@ -208,7 +210,7 @@ do end } _base_0.__index = _base_0 - local _class_0 = setmetatable({ + _class_0 = setmetatable({ __init = function() end, __base = _base_0, __name = "Line" @@ -224,6 +226,7 @@ do Line = _class_0 end do + local _class_0 local _base_0 = { prepare = function() end, render = function(self) @@ -232,7 +235,7 @@ do end } _base_0.__index = _base_0 - local _class_0 = setmetatable({ + _class_0 = setmetatable({ __init = function(self, fn) self.prepare = fn end, @@ -250,6 +253,7 @@ do DelayedLine = _class_0 end do + local _class_0 local _base_0 = { header = "do", footer = "end", @@ -573,7 +577,7 @@ do end } _base_0.__index = _base_0 - local _class_0 = setmetatable({ + _class_0 = setmetatable({ __init = function(self, parent, header, footer) self.parent, self.header, self.footer = parent, header, footer self._lines = Lines() @@ -613,6 +617,7 @@ do Block = _class_0 end do + local _class_0 local _parent_0 = Block local _base_0 = { __tostring = function(self) @@ -634,11 +639,11 @@ do } _base_0.__index = _base_0 setmetatable(_base_0, _parent_0.__base) - local _class_0 = setmetatable({ + _class_0 = setmetatable({ __init = function(self, options) self.options = options self.root = self - return self.__class.__parent.__init(self) + return _class_0.__parent.__init(self) end, __base = _base_0, __name = "RootBlock", diff --git a/moonscript/data.lua b/moonscript/data.lua index 2e159c83..f33f708d 100644 --- a/moonscript/data.lua +++ b/moonscript/data.lua @@ -14,6 +14,7 @@ Set = function(items) end local Stack do + local _class_0 local _base_0 = { __tostring = function(self) return "" @@ -34,7 +35,7 @@ do end } _base_0.__index = _base_0 - local _class_0 = setmetatable({ + _class_0 = setmetatable({ __init = function(self, ...) self:push(...) return nil diff --git a/moonscript/transform.moon b/moonscript/transform.moon index 5db3b5d6..5cd9ec1e 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -680,8 +680,7 @@ Statement = Transformer { @set "super", (block, chain) -> relative_parent = { "chain", - "self" - {"dot", "__class"} + cls_name {"dot", "__parent"} } @@ -729,6 +728,7 @@ Statement = Transformer { else relative_parent + {"declare", { cls_name }} {"declare_glob", "*"} parent_val and .assign_one(parent_cls_name, parent_val) or NOOP diff --git a/moonscript/transform/names.lua b/moonscript/transform/names.lua index c74a3773..b498036e 100644 --- a/moonscript/transform/names.lua +++ b/moonscript/transform/names.lua @@ -4,13 +4,14 @@ local unpack unpack = require("moonscript.util").unpack local LocalName do + local _class_0 local _base_0 = { get_name = function(self) return self.name end } _base_0.__index = _base_0 - local _class_0 = setmetatable({ + _class_0 = setmetatable({ __init = function(self, name) self.name = name self[1] = "temp_name" @@ -30,6 +31,7 @@ do end local NameProxy do + local _class_0 local _base_0 = { get_name = function(self, scope, dont_put) if dont_put == nil then @@ -81,7 +83,7 @@ do end } _base_0.__index = _base_0 - local _class_0 = setmetatable({ + _class_0 = setmetatable({ __init = function(self, prefix) self.prefix = prefix self[1] = "temp_name" diff --git a/moonscript/transform/statements.lua b/moonscript/transform/statements.lua index 169590ea..994df895 100644 --- a/moonscript/transform/statements.lua +++ b/moonscript/transform/statements.lua @@ -5,13 +5,14 @@ do end local Run do + local _class_0 local _base_0 = { call = function(self, state) return self.fn(state) end } _base_0.__index = _base_0 - local _class_0 = setmetatable({ + _class_0 = setmetatable({ __init = function(self, fn) self.fn = fn self[1] = "run" From ae2558ab67d8227b870cee1597a608c98727a924 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 19 Nov 2015 22:47:06 -0800 Subject: [PATCH 317/554] rebuild specs and code --- moonscript/transform.lua | 59 +++++++++++++++++---- spec/outputs/class.lua | 111 ++++++++++++++++++++++++--------------- spec/outputs/export.lua | 3 +- 3 files changed, 120 insertions(+), 53 deletions(-) diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 7a2d18d4..a88b1d2b 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -171,6 +171,7 @@ with_continue_listener = function(body) } end do + local _class_0 local _base_0 = { transform_once = function(self, scope, node, ...) if self.seen_nodes[node] then @@ -217,7 +218,7 @@ do end } _base_0.__index = _base_0 - local _class_0 = setmetatable({ + _class_0 = setmetatable({ __init = function(self, transformers) self.transformers = transformers self.seen_nodes = setmetatable({ }, { @@ -1000,7 +1001,35 @@ Statement = Transformer({ "nil" }, ["then"] = { - parent_cls_name:index("name") + build.assign_one(LocalName("parent"), build.chain({ + base = "rawget", + { + "call", + { + { + "ref", + "cls" + }, + { + "string", + '"', + "__parent" + } + } + } + })), + build["if"]({ + cond = LocalName("parent"), + ["then"] = { + build.chain({ + base = LocalName("parent"), + { + "index", + "name" + } + }) + } + }) } }) insert(class_lookup, { @@ -1098,18 +1127,23 @@ Statement = Transformer({ self:put_name(name) end return self:set("super", function(block, chain) + local relative_parent = { + "chain", + cls_name, + { + "dot", + "__parent" + } + } if chain then local chain_tail = { unpack(chain, 3) } - local new_chain = { - "chain", - parent_cls_name - } local head = chain_tail[1] if head == nil then - return parent_cls_name + return relative_parent end + local new_chain = relative_parent local _exp_1 = head[1] if "call" == _exp_1 then local calling_name = block:get("current_block") @@ -1153,10 +1187,16 @@ Statement = Transformer({ end return new_chain else - return parent_cls_name + return relative_parent end end) end), + { + "declare", + { + cls_name + } + }, { "declare_glob", "*" @@ -1240,6 +1280,7 @@ Statement = Transformer({ end }) do + local _class_0 local _base_0 = { body_idx = { ["for"] = 4, @@ -1300,7 +1341,7 @@ do end } _base_0.__index = _base_0 - local _class_0 = setmetatable({ + _class_0 = setmetatable({ __init = function(self, accum_name) self.accum_name = NameProxy("accum") self.value_name = NameProxy("value") diff --git a/spec/outputs/class.lua b/spec/outputs/class.lua index b9e6c41c..30180620 100644 --- a/spec/outputs/class.lua +++ b/spec/outputs/class.lua @@ -1,5 +1,6 @@ local Hello do + local _class_0 local _base_0 = { hello = function(self) return print(self.test, self.world) @@ -9,7 +10,7 @@ do end } _base_0.__index = _base_0 - local _class_0 = setmetatable({ + _class_0 = setmetatable({ __init = function(self, test, world) self.test, self.world = test, world return print("creating object..") @@ -32,13 +33,14 @@ x:hello() print(x) local Simple do + local _class_0 local _base_0 = { cool = function(self) return print("cool") end } _base_0.__index = _base_0 - local _class_0 = setmetatable({ + _class_0 = setmetatable({ __init = function() end, __base = _base_0, __name = "Simple" @@ -55,11 +57,12 @@ do end local Yikes do + local _class_0 local _parent_0 = Simple local _base_0 = { } _base_0.__index = _base_0 setmetatable(_base_0, _parent_0.__base) - local _class_0 = setmetatable({ + _class_0 = setmetatable({ __init = function(self) return print("created hello") end, @@ -94,13 +97,14 @@ x = Yikes() x:cool() local Hi do + local _class_0 local _base_0 = { cool = function(self, num) return print("num", num) end } _base_0.__index = _base_0 - local _class_0 = setmetatable({ + _class_0 = setmetatable({ __init = function(self, arg) return print("init arg", arg) end, @@ -118,17 +122,18 @@ do Hi = _class_0 end do + local _class_0 local _parent_0 = Hi local _base_0 = { cool = function(self) - return self.__class.__parent.cool(self, 120302) + return _class_0.__parent.cool(self, 120302) end } _base_0.__index = _base_0 setmetatable(_base_0, _parent_0.__base) - local _class_0 = setmetatable({ + _class_0 = setmetatable({ __init = function(self) - return self.__class.__parent.__init(self, "man") + return _class_0.__parent.__init(self, "man") end, __base = _base_0, __name = "Simple", @@ -162,11 +167,12 @@ x:cool() print(x.__class == Simple) local Okay do + local _class_0 local _base_0 = { something = 20323 } _base_0.__index = _base_0 - local _class_0 = setmetatable({ + _class_0 = setmetatable({ __init = function() end, __base = _base_0, __name = "Okay" @@ -183,19 +189,20 @@ do end local Biggie do + local _class_0 local _parent_0 = Okay local _base_0 = { something = function(self) - self.__class.__parent.something(self, 1, 2, 3, 4) - self.__class.__parent.something(another_self, 1, 2, 3, 4) - return assert(self.__class.__parent == Okay) + _class_0.__parent.something(self, 1, 2, 3, 4) + _class_0.__parent.something(another_self, 1, 2, 3, 4) + return assert(_class_0.__parent == Okay) end } _base_0.__index = _base_0 setmetatable(_base_0, _parent_0.__base) - local _class_0 = setmetatable({ + _class_0 = setmetatable({ __init = function(self, ...) - return self.__class.__parent.__init(self, ...) + return _class_0.__parent.__init(self, ...) end, __base = _base_0, __name = "Biggie", @@ -226,13 +233,14 @@ do end local Yeah do + local _class_0 local _base_0 = { okay = function(self) - return self.__class.__parent.something(self, 1, 2, 3, 4) + return _class_0.__parent.something(self, 1, 2, 3, 4) end } _base_0.__index = _base_0 - local _class_0 = setmetatable({ + _class_0 = setmetatable({ __init = function() end, __base = _base_0, __name = "Yeah" @@ -249,13 +257,14 @@ do end local What do + local _class_0 local _base_0 = { something = function(self) return print("val:", self.val) end } _base_0.__index = _base_0 - local _class_0 = setmetatable({ + _class_0 = setmetatable({ __init = function() end, __base = _base_0, __name = "What" @@ -271,11 +280,12 @@ do What = _class_0 end do + local _class_0 local _parent_0 = What local _base_0 = { val = 2323, something = function(self) - local _base_1 = self.__class.__parent + local _base_1 = _class_0.__parent local _fn_0 = _base_1.something return function(...) return _fn_0(self, ...) @@ -284,9 +294,9 @@ do } _base_0.__index = _base_0 setmetatable(_base_0, _parent_0.__base) - local _class_0 = setmetatable({ + _class_0 = setmetatable({ __init = function(self, ...) - return self.__class.__parent.__init(self, ...) + return _class_0.__parent.__init(self, ...) end, __base = _base_0, __name = "Hello", @@ -323,16 +333,17 @@ do end local CoolSuper do + local _class_0 local _base_0 = { hi = function(self) - self.__class.__parent.hi(self, 1, 2, 3, 4)(1, 2, 3, 4) - self.__class.__parent.something(1, 2, 3, 4) - local _ = self.__class.__parent.something(1, 2, 3, 4).world - self.__class.__parent.yeah(self, "world").okay(hi, hi, hi) + _class_0.__parent.hi(self, 1, 2, 3, 4)(1, 2, 3, 4) + _class_0.__parent.something(1, 2, 3, 4) + local _ = _class_0.__parent.something(1, 2, 3, 4).world + _class_0.__parent.yeah(self, "world").okay(hi, hi, hi) _ = something.super - _ = self.__class.__parent.super.super.super + _ = _class_0.__parent.super.super.super do - local _base_1 = self.__class.__parent + local _base_1 = _class_0.__parent local _fn_0 = _base_1.hello _ = function(...) return _fn_0(self, ...) @@ -342,7 +353,7 @@ do end } _base_0.__index = _base_0 - local _class_0 = setmetatable({ + _class_0 = setmetatable({ __init = function() end, __base = _base_0, __name = "CoolSuper" @@ -368,12 +379,13 @@ xx = function(hello, world, cool) end local ClassMan do + local _class_0 local _base_0 = { blue = function(self) end, green = function(self) end } _base_0.__index = _base_0 - local _class_0 = setmetatable({ + _class_0 = setmetatable({ __init = function() end, __base = _base_0, __name = "ClassMan" @@ -403,10 +415,11 @@ self.hello(2, 3, 4) local _ = hello[self].world local Whacko do + local _class_0 local hello local _base_0 = { } _base_0.__index = _base_0 - local _class_0 = setmetatable({ + _class_0 = setmetatable({ __init = function() end, __base = _base_0, __name = "Whacko" @@ -436,9 +449,10 @@ local yyy yyy = function() local Cool do + local _class_0 local _base_0 = { } _base_0.__index = _base_0 - local _class_0 = setmetatable({ + _class_0 = setmetatable({ __init = function() end, __base = _base_0, __name = "Cool" @@ -458,9 +472,10 @@ yyy = function() end end do + local _class_0 local _base_0 = { } _base_0.__index = _base_0 - local _class_0 = setmetatable({ + _class_0 = setmetatable({ __init = function() end, __base = _base_0, __name = "D" @@ -478,9 +493,10 @@ do a.b.c.D = _class_0 end do + local _class_0 local _base_0 = { } _base_0.__index = _base_0 - local _class_0 = setmetatable({ + _class_0 = setmetatable({ __init = function() end, __base = _base_0, __name = "hello" @@ -498,13 +514,14 @@ do a.b["hello"] = _class_0 end do + local _class_0 local _parent_0 = Hello.World local _base_0 = { } _base_0.__index = _base_0 setmetatable(_base_0, _parent_0.__base) - local _class_0 = setmetatable({ + _class_0 = setmetatable({ __init = function(self, ...) - return self.__class.__parent.__init(self, ...) + return _class_0.__parent.__init(self, ...) end, __base = _base_0, __name = "Something", @@ -539,9 +556,10 @@ do end local a do + local _class_0 local _base_0 = { } _base_0.__index = _base_0 - local _class_0 = setmetatable({ + _class_0 = setmetatable({ __init = function() end, __base = _base_0, __name = "a" @@ -559,9 +577,10 @@ end local b local Something do + local _class_0 local _base_0 = { } _base_0.__index = _base_0 - local _class_0 = setmetatable({ + _class_0 = setmetatable({ __init = function() end, __base = _base_0, __name = "Something" @@ -579,13 +598,14 @@ do end local c do + local _class_0 local _parent_0 = Hello local _base_0 = { } _base_0.__index = _base_0 setmetatable(_base_0, _parent_0.__base) - local _class_0 = setmetatable({ + _class_0 = setmetatable({ __init = function(self, ...) - return self.__class.__parent.__init(self, ...) + return _class_0.__parent.__init(self, ...) end, __base = _base_0, __name = "Something", @@ -617,13 +637,14 @@ do end local d do + local _class_0 local _parent_0 = World local _base_0 = { } _base_0.__index = _base_0 setmetatable(_base_0, _parent_0.__base) - local _class_0 = setmetatable({ + _class_0 = setmetatable({ __init = function(self, ...) - return self.__class.__parent.__init(self, ...) + return _class_0.__parent.__init(self, ...) end, __base = _base_0, __name = "d", @@ -655,9 +676,10 @@ end print(((function() local WhatsUp do + local _class_0 local _base_0 = { } _base_0.__index = _base_0 - local _class_0 = setmetatable({ + _class_0 = setmetatable({ __init = function() end, __base = _base_0, __name = "WhatsUp" @@ -675,9 +697,10 @@ print(((function() end end)()).__name) do + local _class_0 local _base_0 = { } _base_0.__index = _base_0 - local _class_0 = setmetatable({ + _class_0 = setmetatable({ __init = function() end, __base = _base_0, __name = "Something" @@ -695,10 +718,11 @@ do Something = _class_0 end do + local _class_0 local val, insert local _base_0 = { } _base_0.__index = _base_0 - local _class_0 = setmetatable({ + _class_0 = setmetatable({ __init = function(self) return print(insert, val) end, @@ -719,9 +743,10 @@ do Something = _class_0 end do + local _class_0 local _base_0 = { } _base_0.__index = _base_0 - local _class_0 = setmetatable({ + _class_0 = setmetatable({ __init = hi, __base = _base_0, __name = "X" diff --git a/spec/outputs/export.lua b/spec/outputs/export.lua index 72ebadea..08fb4ce8 100644 --- a/spec/outputs/export.lua +++ b/spec/outputs/export.lua @@ -4,11 +4,12 @@ do end do do + local _class_0 local _base_0 = { umm = "cool" } _base_0.__index = _base_0 - local _class_0 = setmetatable({ + _class_0 = setmetatable({ __init = function() end, __base = _base_0, __name = "Something" From d91fbbe4962f9a9e70457804665f931d98502c92 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 5 Dec 2015 21:34:32 -0800 Subject: [PATCH 318/554] count --- Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index c4d3c8d0..8ddcd12c 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: test local compile compile_system watch lint +.PHONY: test local compile compile_system watch lint count test: busted @@ -23,3 +23,6 @@ watch: lint: moonc -l moonscript moon bin + +count: + wc -l $$(git ls-files | grep 'moon$$') | sort -n | tail From d73c0a1d3fecef6cab8045c54a9a3d22a302bc35 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 5 Dec 2015 21:38:08 -0800 Subject: [PATCH 319/554] unindent super code --- moonscript/transform.moon | 93 +++++++++++++++++++++------------------ 1 file changed, 49 insertions(+), 44 deletions(-) diff --git a/moonscript/transform.moon b/moonscript/transform.moon index 5cd9ec1e..d04a236f 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -684,49 +684,48 @@ Statement = Transformer { {"dot", "__parent"} } - if chain - chain_tail = { unpack chain, 3 } - head = chain_tail[1] - - if head == nil - return relative_parent - - new_chain = relative_parent - - switch head[1] - -- calling super, inject calling name and self into chain - when "call" - calling_name = block\get"current_block" - chain_tail[1] = {"call", {"self", unpack head[2]}} - - if ntype(calling_name) == "key_literal" - insert new_chain, {"dot", calling_name[2]} - else - insert new_chain, {"index", calling_name} - - -- colon call on super, replace class with self as first arg - when "colon" - call = chain_tail[2] - -- calling chain tail - if call and call[1] == "call" - chain_tail[1] = { - "dot" - head[2] + return relative_parent unless chain + + chain_tail = { unpack chain, 3 } + head = chain_tail[1] + + if head == nil + return relative_parent + + new_chain = relative_parent + + switch head[1] + -- calling super, inject calling name and self into chain + when "call" + calling_name = block\get"current_block" + assert calling_name, "missing calling name" + chain_tail[1] = {"call", {"self", unpack head[2]}} + + if ntype(calling_name) == "key_literal" + insert new_chain, {"dot", calling_name[2]} + else + insert new_chain, {"index", calling_name} + + -- colon call on super, replace class with self as first arg + when "colon" + call = chain_tail[2] + -- calling chain tail + if call and call[1] == "call" + chain_tail[1] = { + "dot" + head[2] + } + + chain_tail[2] = { + "call" + { + "self" + unpack call[2] } + } - chain_tail[2] = { - "call" - { - "self" - unpack call[2] - } - } - - insert new_chain, item for item in *chain_tail - - new_chain - else - relative_parent + insert new_chain, item for item in *chain_tail + new_chain {"declare", { cls_name }} {"declare_glob", "*"} @@ -939,9 +938,15 @@ Value = Transformer { node - if: (node) => build.block_exp { node } - unless: (node) =>build.block_exp { node } - with: (node) => build.block_exp { node } + if: (node) => + build.block_exp { node } + + unless: (node) => + build.block_exp { node } + + with: (node) => + build.block_exp { node } + switch: (node) => build.block_exp { node } From 53ef9fe5045e3e5996224ac28df684e65a679ced Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 5 Dec 2015 21:38:29 -0800 Subject: [PATCH 320/554] move transformer to separate class --- moonscript/transform.lua | 160 +++++++++++--------------------------- moonscript/transform.moon | 40 +--------- 2 files changed, 49 insertions(+), 151 deletions(-) diff --git a/moonscript/transform.lua b/moonscript/transform.lua index a88b1d2b..922bef9a 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -17,11 +17,13 @@ do local _obj_0 = require("moonscript.transform.statements") Run, transform_last_stm, last_stm, chain_is_stub = _obj_0.Run, _obj_0.transform_last_stm, _obj_0.last_stm, _obj_0.chain_is_stub end +local Transformer +Transformer = require("moonscript.transform.transformer").Transformer local destructure = require("moonscript.transform.destructure") local NOOP = { "noop" } -local is_singular, extract_declarations, expand_elseif_assign, constructor_name, with_continue_listener, Transformer, construct_comprehension, Statement, Accumulator, default_accumulator, implicitly_return, Value +local is_singular, extract_declarations, expand_elseif_assign, constructor_name, with_continue_listener, construct_comprehension, Statement, Accumulator, default_accumulator, implicitly_return, Value is_singular = function(body) if #body ~= 1 then return false @@ -170,74 +172,6 @@ with_continue_listener = function(body) end) } end -do - local _class_0 - local _base_0 = { - transform_once = function(self, scope, node, ...) - if self.seen_nodes[node] then - return node - end - self.seen_nodes[node] = true - local transformer = self.transformers[ntype(node)] - if transformer then - return transformer(scope, node, ...) or node - else - return node - end - end, - transform = function(self, scope, node, ...) - if self.seen_nodes[node] then - return node - end - self.seen_nodes[node] = true - while true do - local transformer = self.transformers[ntype(node)] - local res - if transformer then - res = transformer(scope, node, ...) or node - else - res = node - end - if res == node then - return node - end - node = res - end - return node - end, - bind = function(self, scope) - return function(...) - return self:transform(scope, ...) - end - end, - __call = function(self, ...) - return self:transform(...) - end, - can_transform = function(self, node) - return self.transformers[ntype(node)] ~= nil - end - } - _base_0.__index = _base_0 - _class_0 = setmetatable({ - __init = function(self, transformers) - self.transformers = transformers - self.seen_nodes = setmetatable({ }, { - __mode = "k" - }) - end, - __base = _base_0, - __name = "Transformer" - }, { - __index = _base_0, - __call = function(cls, ...) - local _self_0 = setmetatable({}, _base_0) - cls.__init(_self_0, ...) - return _self_0 - end - }) - _base_0.__class = _class_0 - Transformer = _class_0 -end construct_comprehension = function(inner, clauses) local current_stms = inner for _, clause in reversed(clauses) do @@ -1135,60 +1069,60 @@ Statement = Transformer({ "__parent" } } - if chain then - local chain_tail = { - unpack(chain, 3) + if not (chain) then + return relative_parent + end + local chain_tail = { + unpack(chain, 3) + } + local head = chain_tail[1] + if head == nil then + return relative_parent + end + local new_chain = relative_parent + local _exp_1 = head[1] + if "call" == _exp_1 then + local calling_name = block:get("current_block") + assert(calling_name, "missing calling name") + chain_tail[1] = { + "call", + { + "self", + unpack(head[2]) + } } - local head = chain_tail[1] - if head == nil then - return relative_parent + if ntype(calling_name) == "key_literal" then + insert(new_chain, { + "dot", + calling_name[2] + }) + else + insert(new_chain, { + "index", + calling_name + }) end - local new_chain = relative_parent - local _exp_1 = head[1] - if "call" == _exp_1 then - local calling_name = block:get("current_block") + elseif "colon" == _exp_1 then + local call = chain_tail[2] + if call and call[1] == "call" then chain_tail[1] = { + "dot", + head[2] + } + chain_tail[2] = { "call", { "self", - unpack(head[2]) + unpack(call[2]) } } - if ntype(calling_name) == "key_literal" then - insert(new_chain, { - "dot", - calling_name[2] - }) - else - insert(new_chain, { - "index", - calling_name - }) - end - elseif "colon" == _exp_1 then - local call = chain_tail[2] - if call and call[1] == "call" then - chain_tail[1] = { - "dot", - head[2] - } - chain_tail[2] = { - "call", - { - "self", - unpack(call[2]) - } - } - end end - for _index_0 = 1, #chain_tail do - local item = chain_tail[_index_0] - insert(new_chain, item) - end - return new_chain - else - return relative_parent end + for _index_0 = 1, #chain_tail do + local item = chain_tail[_index_0] + insert(new_chain, item) + end + return new_chain end) end), { diff --git a/moonscript/transform.moon b/moonscript/transform.moon index d04a236f..27127d2d 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -10,6 +10,8 @@ import insert from table import NameProxy, LocalName from require "moonscript.transform.names" import Run, transform_last_stm, last_stm, chain_is_stub from require "moonscript.transform.statements" +import Transformer from require "moonscript.transform.transformer" + destructure = require "moonscript.transform.destructure" NOOP = {"noop"} @@ -93,44 +95,6 @@ with_continue_listener = (body) -> } -class Transformer - new: (@transformers) => - @seen_nodes = setmetatable {}, __mode: "k" - - transform_once: (scope, node, ...) => - return node if @seen_nodes[node] - @seen_nodes[node] = true - - transformer = @transformers[ntype node] - if transformer - transformer(scope, node, ...) or node - else - node - - transform: (scope, node, ...) => - return node if @seen_nodes[node] - - @seen_nodes[node] = true - while true - transformer = @transformers[ntype node] - res = if transformer - transformer(scope, node, ...) or node - else - node - - return node if res == node - node = res - - node - - bind: (scope) => - (...) -> @transform scope, ... - - __call: (...) => @transform ... - - can_transform: (node) => - @transformers[ntype node] != nil - construct_comprehension = (inner, clauses) -> current_stms = inner for _, clause in reversed clauses From 76af9964fe7e1186e3080d7a18f4db65b529b115 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 5 Dec 2015 23:07:42 -0800 Subject: [PATCH 321/554] refactor apart transfromers --- moonscript/cmd/lint.lua | 3 + moonscript/cmd/lint.moon | 1 + moonscript/parse.lua | 4 +- moonscript/parse.moon | 2 +- moonscript/parse/util.lua | 12 - moonscript/parse/util.moon | 8 +- moonscript/transform.lua | 1573 +------------------------ moonscript/transform.moon | 978 +-------------- moonscript/transform/accumulator.lua | 110 ++ moonscript/transform/accumulator.moon | 71 ++ moonscript/transform/statement.lua | 1161 ++++++++++++++++++ moonscript/transform/statement.moon | 720 +++++++++++ moonscript/transform/statements.lua | 89 +- moonscript/transform/statements.moon | 56 +- moonscript/transform/transformer.lua | 74 ++ moonscript/transform/transformer.moon | 42 + moonscript/transform/value.lua | 261 ++++ moonscript/transform/value.moon | 162 +++ moonscript/types.lua | 6 +- moonscript/types.moon | 3 + 20 files changed, 2760 insertions(+), 2576 deletions(-) create mode 100644 moonscript/transform/accumulator.lua create mode 100644 moonscript/transform/accumulator.moon create mode 100644 moonscript/transform/statement.lua create mode 100644 moonscript/transform/statement.moon create mode 100644 moonscript/transform/transformer.lua create mode 100644 moonscript/transform/transformer.moon create mode 100644 moonscript/transform/value.lua create mode 100644 moonscript/transform/value.moon diff --git a/moonscript/cmd/lint.lua b/moonscript/cmd/lint.lua index 50509e57..55f018b5 100644 --- a/moonscript/cmd/lint.lua +++ b/moonscript/cmd/lint.lua @@ -65,6 +65,9 @@ do end end, lint_check_unused = function(self) + do + return + end if not (self.lint_unused_names and next(self.lint_unused_names)) then return end diff --git a/moonscript/cmd/lint.moon b/moonscript/cmd/lint.moon index 103c25ed..853bab59 100644 --- a/moonscript/cmd/lint.moon +++ b/moonscript/cmd/lint.moon @@ -105,6 +105,7 @@ class LinterBlock extends Block @parent\lint_mark_used name lint_check_unused: => + do return return unless @lint_unused_names and next @lint_unused_names names_by_position = {} diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 53c12f05..49b673dd 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -27,10 +27,10 @@ Num = Space * (Num / function(v) v } end) -local Indent, Cut, ensure, extract_line, mark, pos, flatten_or_mark, is_assignable, check_assignable, format_assign, format_single_assign, sym, symx, simple_string, wrap_func_arg, join_chain, flatten_string_chain, wrap_decorator, check_lua_string, self_assign +local Indent, Cut, ensure, extract_line, mark, pos, flatten_or_mark, is_assignable, check_assignable, format_assign, format_single_assign, sym, symx, simple_string, wrap_func_arg, join_chain, wrap_decorator, check_lua_string, self_assign do local _obj_0 = require("moonscript.parse.util") - Indent, Cut, ensure, extract_line, mark, pos, flatten_or_mark, is_assignable, check_assignable, format_assign, format_single_assign, sym, symx, simple_string, wrap_func_arg, join_chain, flatten_string_chain, wrap_decorator, check_lua_string, self_assign = _obj_0.Indent, _obj_0.Cut, _obj_0.ensure, _obj_0.extract_line, _obj_0.mark, _obj_0.pos, _obj_0.flatten_or_mark, _obj_0.is_assignable, _obj_0.check_assignable, _obj_0.format_assign, _obj_0.format_single_assign, _obj_0.sym, _obj_0.symx, _obj_0.simple_string, _obj_0.wrap_func_arg, _obj_0.join_chain, _obj_0.flatten_string_chain, _obj_0.wrap_decorator, _obj_0.check_lua_string, _obj_0.self_assign + Indent, Cut, ensure, extract_line, mark, pos, flatten_or_mark, is_assignable, check_assignable, format_assign, format_single_assign, sym, symx, simple_string, wrap_func_arg, join_chain, wrap_decorator, check_lua_string, self_assign = _obj_0.Indent, _obj_0.Cut, _obj_0.ensure, _obj_0.extract_line, _obj_0.mark, _obj_0.pos, _obj_0.flatten_or_mark, _obj_0.is_assignable, _obj_0.check_assignable, _obj_0.format_assign, _obj_0.format_single_assign, _obj_0.sym, _obj_0.symx, _obj_0.simple_string, _obj_0.wrap_func_arg, _obj_0.join_chain, _obj_0.wrap_decorator, _obj_0.check_lua_string, _obj_0.self_assign end local build_grammar = wrap_env(debug_grammar, function(root) local _indent = Stack(0) diff --git a/moonscript/parse.moon b/moonscript/parse.moon index 96c26e5f..0c6bc823 100644 --- a/moonscript/parse.moon +++ b/moonscript/parse.moon @@ -29,7 +29,7 @@ Num = Space * (Num / (v) -> {"number", v}) :Indent, :Cut, :ensure, :extract_line, :mark, :pos, :flatten_or_mark, :is_assignable, :check_assignable, :format_assign, :format_single_assign, :sym, :symx, :simple_string, :wrap_func_arg, :join_chain, - :flatten_string_chain, :wrap_decorator, :check_lua_string, :self_assign + :wrap_decorator, :check_lua_string, :self_assign } = require "moonscript.parse.util" diff --git a/moonscript/parse/util.lua b/moonscript/parse/util.lua index a93665dc..e9d4554b 100644 --- a/moonscript/parse/util.lua +++ b/moonscript/parse/util.lua @@ -197,17 +197,6 @@ join_chain = function(callee, args) args } end -local flatten_string_chain -flatten_string_chain = function(str, chain, args) - if not (chain) then - return str - end - return flatten_chain({ - "chain", - str, - unpack(chain) - }, args) -end local wrap_decorator wrap_decorator = function(stm, dec) if not (dec) then @@ -254,7 +243,6 @@ return { simple_string = simple_string, wrap_func_arg = wrap_func_arg, join_chain = join_chain, - flatten_string_chain = flatten_string_chain, wrap_decorator = wrap_decorator, check_lua_string = check_lua_string, self_assign = self_assign diff --git a/moonscript/parse/util.moon b/moonscript/parse/util.moon index 2039e3bd..af33279e 100644 --- a/moonscript/parse/util.moon +++ b/moonscript/parse/util.moon @@ -139,10 +139,6 @@ join_chain = (callee, args) -> {"chain", callee, args} -flatten_string_chain = (str, chain, args) -> - return str unless chain - flatten_chain {"chain", str, unpack chain}, args - -- constructor for decorator node wrap_decorator = (stm, dec) -> return stm unless dec @@ -157,5 +153,5 @@ self_assign = (name, pos) -> { :Indent, :Cut, :ensure, :extract_line, :mark, :pos, :flatten_or_mark, :is_assignable, :check_assignable, :format_assign, :format_single_assign, - :sym, :symx, :simple_string, :wrap_func_arg, :join_chain, - :flatten_string_chain, :wrap_decorator, :check_lua_string, :self_assign } + :sym, :symx, :simple_string, :wrap_func_arg, :join_chain, :wrap_decorator, + :check_lua_string, :self_assign } diff --git a/moonscript/transform.lua b/moonscript/transform.lua index 922bef9a..c95f14d3 100644 --- a/moonscript/transform.lua +++ b/moonscript/transform.lua @@ -1,1573 +1,4 @@ -local types = require("moonscript.types") -local util = require("moonscript.util") -local data = require("moonscript.data") -local reversed, unpack -reversed, unpack = util.reversed, util.unpack -local ntype, mtype, build, smart_node, is_slice, value_is_singular -ntype, mtype, build, smart_node, is_slice, value_is_singular = types.ntype, types.mtype, types.build, types.smart_node, types.is_slice, types.value_is_singular -local insert -insert = table.insert -local NameProxy, LocalName -do - local _obj_0 = require("moonscript.transform.names") - NameProxy, LocalName = _obj_0.NameProxy, _obj_0.LocalName -end -local Run, transform_last_stm, last_stm, chain_is_stub -do - local _obj_0 = require("moonscript.transform.statements") - Run, transform_last_stm, last_stm, chain_is_stub = _obj_0.Run, _obj_0.transform_last_stm, _obj_0.last_stm, _obj_0.chain_is_stub -end -local Transformer -Transformer = require("moonscript.transform.transformer").Transformer -local destructure = require("moonscript.transform.destructure") -local NOOP = { - "noop" -} -local is_singular, extract_declarations, expand_elseif_assign, constructor_name, with_continue_listener, construct_comprehension, Statement, Accumulator, default_accumulator, implicitly_return, Value -is_singular = function(body) - if #body ~= 1 then - return false - end - if "group" == ntype(body) then - return is_singular(body[2]) - else - return body[1] - end -end -extract_declarations = function(self, body, start, out) - if body == nil then - body = self.current_stms - end - if start == nil then - start = self.current_stm_i + 1 - end - if out == nil then - out = { } - end - for i = start, #body do - local _continue_0 = false - repeat - local stm = body[i] - if stm == nil then - _continue_0 = true - break - end - stm = self.transform.statement(stm) - body[i] = stm - local _exp_0 = stm[1] - if "assign" == _exp_0 or "declare" == _exp_0 then - local _list_0 = stm[2] - for _index_0 = 1, #_list_0 do - local name = _list_0[_index_0] - if ntype(name) == "ref" then - insert(out, name) - elseif type(name) == "string" then - insert(out, name) - end - end - elseif "group" == _exp_0 then - extract_declarations(self, stm[2], 1, out) - end - _continue_0 = true - until true - if not _continue_0 then - break - end - end - return out -end -expand_elseif_assign = function(ifstm) - for i = 4, #ifstm do - local case = ifstm[i] - if ntype(case) == "elseif" and ntype(case[2]) == "assign" then - local split = { - unpack(ifstm, 1, i - 1) - } - insert(split, { - "else", - { - { - "if", - case[2], - case[3], - unpack(ifstm, i + 1) - } - } - }) - return split - end - end - return ifstm -end -constructor_name = "new" -with_continue_listener = function(body) - local continue_name = nil - return { - Run(function(self) - return self:listen("continue", function() - if not (continue_name) then - continue_name = NameProxy("continue") - self:put_name(continue_name) - end - return continue_name - end) - end), - build.group(body), - Run(function(self) - if not (continue_name) then - return - end - local last = last_stm(body) - local enclose_lines = types.terminating[last and ntype(last)] - self:put_name(continue_name, nil) - return self:splice(function(lines) - if enclose_lines then - lines = { - "do", - { - lines - } - } - end - return { - { - "assign", - { - continue_name - }, - { - "false" - } - }, - { - "repeat", - "true", - { - lines, - { - "assign", - { - continue_name - }, - { - "true" - } - } - } - }, - { - "if", - { - "not", - continue_name - }, - { - { - "break" - } - } - } - } - end) - end) - } -end -construct_comprehension = function(inner, clauses) - local current_stms = inner - for _, clause in reversed(clauses) do - local t = clause[1] - local _exp_0 = t - if "for" == _exp_0 then - local name, bounds - _, name, bounds = clause[1], clause[2], clause[3] - current_stms = { - "for", - name, - bounds, - current_stms - } - elseif "foreach" == _exp_0 then - local names, iter - _, names, iter = clause[1], clause[2], clause[3] - current_stms = { - "foreach", - names, - { - iter - }, - current_stms - } - elseif "when" == _exp_0 then - local cond - _, cond = clause[1], clause[2] - current_stms = { - "if", - cond, - current_stms - } - else - current_stms = error("Unknown comprehension clause: " .. t) - end - current_stms = { - current_stms - } - end - return current_stms[1] -end -Statement = Transformer({ - transform = function(self, tuple) - local _, node, fn - _, node, fn = tuple[1], tuple[2], tuple[3] - return fn(node) - end, - root_stms = function(self, body) - return transform_last_stm(body, implicitly_return(self)) - end, - ["return"] = function(self, node) - local ret_val = node[2] - local ret_val_type = ntype(ret_val) - if ret_val_type == "explist" and #ret_val == 2 then - ret_val = ret_val[2] - ret_val_type = ntype(ret_val) - end - if types.cascading[ret_val_type] then - return implicitly_return(self)(ret_val) - end - if ret_val_type == "chain" or ret_val_type == "comprehension" or ret_val_type == "tblcomprehension" then - ret_val = Value:transform_once(self, ret_val) - if ntype(ret_val) == "block_exp" then - return build.group(transform_last_stm(ret_val[2], function(stm) - return { - "return", - stm - } - end)) - end - end - node[2] = ret_val - return node - end, - declare_glob = function(self, node) - local names = extract_declarations(self) - if node[2] == "^" then - do - local _accum_0 = { } - local _len_0 = 1 - for _index_0 = 1, #names do - local _continue_0 = false - repeat - local name = names[_index_0] - if not (name[2]:match("^%u")) then - _continue_0 = true - break - end - local _value_0 = name - _accum_0[_len_0] = _value_0 - _len_0 = _len_0 + 1 - _continue_0 = true - until true - if not _continue_0 then - break - end - end - names = _accum_0 - end - end - return { - "declare", - names - } - end, - assign = function(self, node) - local names, values = unpack(node, 2) - local num_values = #values - local num_names = #values - if num_names == 1 and num_values == 1 then - local first_value = values[1] - local first_name = names[1] - local first_type = ntype(first_value) - if first_type == "chain" then - first_value = Value:transform_once(self, first_value) - first_type = ntype(first_value) - end - local _exp_0 = ntype(first_value) - if "block_exp" == _exp_0 then - local block_body = first_value[2] - local idx = #block_body - block_body[idx] = build.assign_one(first_name, block_body[idx]) - return build.group({ - { - "declare", - { - first_name - } - }, - { - "do", - block_body - } - }) - elseif "comprehension" == _exp_0 or "tblcomprehension" == _exp_0 or "foreach" == _exp_0 or "for" == _exp_0 or "while" == _exp_0 then - return build.assign_one(first_name, Value:transform_once(self, first_value)) - else - values[1] = first_value - end - end - local transformed - if num_values == 1 then - local value = values[1] - local t = ntype(value) - if t == "decorated" then - value = self.transform.statement(value) - t = ntype(value) - end - if types.cascading[t] then - local ret - ret = function(stm) - if types.is_value(stm) then - return { - "assign", - names, - { - stm - } - } - else - return stm - end - end - transformed = build.group({ - { - "declare", - names - }, - self.transform.statement(value, ret, node) - }) - end - end - node = transformed or node - if destructure.has_destructure(names) then - return destructure.split_assign(self, node) - end - return 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 - local cls = smart_node(node[3]) - return build.group({ - { - "export", - { - cls.name - } - }, - cls - }) - else - return build.group({ - { - "export", - node[2] - }, - build.assign({ - names = node[2], - values = node[3] - }) - }) - end - else - return nil - end - end, - update = function(self, node) - local _, name, op, exp = unpack(node) - local op_final = op:match("^(.+)=$") - if not op_final then - error("Unknown op: " .. op) - end - if not (value_is_singular(exp)) then - exp = { - "parens", - exp - } - end - return build.assign_one(name, { - "exp", - name, - op_final, - exp - }) - end, - import = function(self, node) - local _, names, source = unpack(node) - local table_values - do - local _accum_0 = { } - local _len_0 = 1 - for _index_0 = 1, #names do - local name = names[_index_0] - local dest_name - if ntype(name) == "colon" then - dest_name = name[2] - else - dest_name = name - end - local _value_0 = { - { - "key_literal", - name - }, - dest_name - } - _accum_0[_len_0] = _value_0 - _len_0 = _len_0 + 1 - end - table_values = _accum_0 - end - local dest = { - "table", - table_values - } - return { - "assign", - { - dest - }, - { - source - }, - [-1] = node[-1] - } - end, - comprehension = function(self, node, action) - local _, exp, clauses = unpack(node) - action = action or function(exp) - return { - exp - } - end - return construct_comprehension(action(exp), clauses) - end, - ["do"] = function(self, node, ret) - if ret then - node[2] = transform_last_stm(node[2], ret) - end - return node - end, - decorated = function(self, node) - local stm, dec = unpack(node, 2) - local wrapped - local _exp_0 = dec[1] - if "if" == _exp_0 then - local cond, fail = unpack(dec, 2) - if fail then - fail = { - "else", - { - fail - } - } - end - wrapped = { - "if", - cond, - { - stm - }, - fail - } - elseif "unless" == _exp_0 then - wrapped = { - "unless", - dec[2], - { - stm - } - } - elseif "comprehension" == _exp_0 then - wrapped = { - "comprehension", - stm, - dec[2] - } - else - wrapped = error("Unknown decorator " .. dec[1]) - end - if ntype(stm) == "assign" then - wrapped = build.group({ - build.declare({ - names = (function() - local _accum_0 = { } - local _len_0 = 1 - local _list_0 = stm[2] - for _index_0 = 1, #_list_0 do - local name = _list_0[_index_0] - if ntype(name) == "ref" then - _accum_0[_len_0] = name - _len_0 = _len_0 + 1 - end - end - return _accum_0 - end)() - }), - wrapped - }) - end - return wrapped - end, - unless = function(self, node) - return { - "if", - { - "not", - { - "parens", - node[2] - } - }, - unpack(node, 3) - } - end, - ["if"] = function(self, node, ret) - if ntype(node[2]) == "assign" then - local _, assign, body = unpack(node) - if destructure.has_destructure(assign[2]) then - local name = NameProxy("des") - body = { - destructure.build_assign(self, assign[2][1], name), - build.group(node[3]) - } - return build["do"]({ - build.assign_one(name, assign[3][1]), - { - "if", - name, - body, - unpack(node, 4) - } - }) - else - local name = assign[2][1] - return build["do"]({ - assign, - { - "if", - name, - unpack(node, 3) - } - }) - end - end - node = expand_elseif_assign(node) - if ret then - smart_node(node) - node['then'] = transform_last_stm(node['then'], ret) - for i = 4, #node do - local case = node[i] - local body_idx = #node[i] - case[body_idx] = transform_last_stm(case[body_idx], ret) - end - end - return node - end, - with = function(self, node, ret) - local exp, block = unpack(node, 2) - local copy_scope = true - local scope_name, named_assign - do - local last = last_stm(block) - if last then - if types.terminating[ntype(last)] then - ret = false - end - end - end - if ntype(exp) == "assign" then - local names, values = unpack(exp, 2) - local first_name = names[1] - if ntype(first_name) == "ref" then - scope_name = first_name - named_assign = exp - exp = values[1] - copy_scope = false - else - scope_name = NameProxy("with") - exp = values[1] - values[1] = scope_name - named_assign = { - "assign", - names, - values - } - end - elseif self:is_local(exp) then - scope_name = exp - copy_scope = false - end - scope_name = scope_name or NameProxy("with") - local out = build["do"]({ - copy_scope and build.assign_one(scope_name, exp) or NOOP, - named_assign or NOOP, - Run(function(self) - return self:set("scope_var", scope_name) - end), - unpack(block) - }) - if ret then - table.insert(out[2], ret(scope_name)) - end - return out - end, - foreach = function(self, node, _) - smart_node(node) - local source = unpack(node.iter) - local destructures = { } - do - local _accum_0 = { } - local _len_0 = 1 - for i, name in ipairs(node.names) do - if ntype(name) == "table" then - do - local proxy = NameProxy("des") - insert(destructures, destructure.build_assign(self, name, proxy)) - _accum_0[_len_0] = proxy - end - else - _accum_0[_len_0] = name - end - _len_0 = _len_0 + 1 - end - node.names = _accum_0 - end - if next(destructures) then - insert(destructures, build.group(node.body)) - node.body = destructures - end - if ntype(source) == "unpack" then - local list = source[2] - local index_name = NameProxy("index") - local list_name = self:is_local(list) and list or NameProxy("list") - local slice_var = nil - local bounds - if is_slice(list) then - local slice = list[#list] - table.remove(list) - table.remove(slice, 1) - if self:is_local(list) then - list_name = list - end - if slice[2] and slice[2] ~= "" then - local max_tmp_name = NameProxy("max") - slice_var = build.assign_one(max_tmp_name, slice[2]) - slice[2] = { - "exp", - max_tmp_name, - "<", - 0, - "and", - { - "length", - list_name - }, - "+", - max_tmp_name, - "or", - max_tmp_name - } - else - slice[2] = { - "length", - list_name - } - end - bounds = slice - else - bounds = { - 1, - { - "length", - list_name - } - } - end - return build.group({ - list_name ~= list and build.assign_one(list_name, list) or NOOP, - slice_var or NOOP, - build["for"]({ - name = index_name, - bounds = bounds, - body = { - { - "assign", - node.names, - { - NameProxy.index(list_name, index_name) - } - }, - build.group(node.body) - } - }) - }) - end - node.body = with_continue_listener(node.body) - end, - ["while"] = function(self, node) - smart_node(node) - node.body = with_continue_listener(node.body) - end, - ["for"] = function(self, node) - smart_node(node) - node.body = with_continue_listener(node.body) - end, - switch = function(self, node, ret) - local _, exp, conds = unpack(node) - local exp_name = NameProxy("exp") - local convert_cond - convert_cond = function(cond) - local t, case_exps, body = unpack(cond) - local out = { } - insert(out, t == "case" and "elseif" or "else") - if t ~= "else" then - local cond_exp = { } - for i, case in ipairs(case_exps) do - if i == 1 then - insert(cond_exp, "exp") - else - insert(cond_exp, "or") - end - if not (value_is_singular(case)) then - case = { - "parens", - case - } - end - insert(cond_exp, { - "exp", - case, - "==", - exp_name - }) - end - insert(out, cond_exp) - else - body = case_exps - end - if ret then - body = transform_last_stm(body, ret) - end - insert(out, body) - return out - end - local first = true - local if_stm = { - "if" - } - for _index_0 = 1, #conds do - local cond = conds[_index_0] - local if_cond = convert_cond(cond) - if first then - first = false - insert(if_stm, if_cond[2]) - insert(if_stm, if_cond[3]) - else - insert(if_stm, if_cond) - end - end - return build.group({ - build.assign_one(exp_name, exp), - if_stm - }) - end, - class = function(self, node, ret, parent_assign) - local _, name, parent_val, body = unpack(node) - if parent_val == "" then - parent_val = nil - end - local statements = { } - local properties = { } - for _index_0 = 1, #body do - local item = body[_index_0] - local _exp_0 = item[1] - if "stm" == _exp_0 then - insert(statements, item[2]) - elseif "props" == _exp_0 then - for _index_1 = 2, #item do - local tuple = item[_index_1] - if ntype(tuple[1]) == "self" then - insert(statements, build.assign_one(unpack(tuple))) - else - insert(properties, tuple) - end - end - end - end - local constructor - do - local _accum_0 = { } - local _len_0 = 1 - for _index_0 = 1, #properties do - local _continue_0 = false - repeat - local tuple = properties[_index_0] - local key = tuple[1] - local _value_0 - if key[1] == "key_literal" and key[2] == constructor_name then - constructor = tuple[2] - _continue_0 = true - break - else - _value_0 = tuple - end - _accum_0[_len_0] = _value_0 - _len_0 = _len_0 + 1 - _continue_0 = true - until true - if not _continue_0 then - break - end - end - properties = _accum_0 - end - local parent_cls_name = NameProxy("parent") - local base_name = NameProxy("base") - local self_name = NameProxy("self") - local cls_name = NameProxy("class") - if not (constructor) then - if parent_val then - constructor = build.fndef({ - args = { - { - "..." - } - }, - arrow = "fat", - body = { - build.chain({ - base = "super", - { - "call", - { - "..." - } - } - }) - } - }) - else - constructor = build.fndef() - end - end - local real_name = name or parent_assign and parent_assign[2][1] - local _exp_0 = ntype(real_name) - if "chain" == _exp_0 then - local last = real_name[#real_name] - local _exp_1 = ntype(last) - if "dot" == _exp_1 then - real_name = { - "string", - '"', - last[2] - } - elseif "index" == _exp_1 then - real_name = last[2] - else - real_name = "nil" - end - elseif "nil" == _exp_0 then - real_name = "nil" - else - local name_t = type(real_name) - local flattened_name - if name_t == "string" then - flattened_name = real_name - elseif name_t == "table" and real_name[1] == "ref" then - flattened_name = real_name[2] - else - flattened_name = error("don't know how to extract name from " .. tostring(name_t)) - end - real_name = { - "string", - '"', - flattened_name - } - end - local cls = build.table({ - { - "__init", - constructor - }, - { - "__base", - base_name - }, - { - "__name", - real_name - }, - parent_val and { - "__parent", - parent_cls_name - } or nil - }) - local class_index - if parent_val then - local class_lookup = build["if"]({ - cond = { - "exp", - { - "ref", - "val" - }, - "==", - "nil" - }, - ["then"] = { - build.assign_one(LocalName("parent"), build.chain({ - base = "rawget", - { - "call", - { - { - "ref", - "cls" - }, - { - "string", - '"', - "__parent" - } - } - } - })), - build["if"]({ - cond = LocalName("parent"), - ["then"] = { - build.chain({ - base = LocalName("parent"), - { - "index", - "name" - } - }) - } - }) - } - }) - insert(class_lookup, { - "else", - { - "val" - } - }) - class_index = build.fndef({ - args = { - { - "cls" - }, - { - "name" - } - }, - body = { - build.assign_one(LocalName("val"), build.chain({ - base = "rawget", - { - "call", - { - base_name, - { - "ref", - "name" - } - } - } - })), - class_lookup - } - }) - else - class_index = base_name - end - local cls_mt = build.table({ - { - "__index", - class_index - }, - { - "__call", - build.fndef({ - args = { - { - "cls" - }, - { - "..." - } - }, - body = { - build.assign_one(self_name, build.chain({ - base = "setmetatable", - { - "call", - { - "{}", - base_name - } - } - })), - build.chain({ - base = "cls.__init", - { - "call", - { - self_name, - "..." - } - } - }), - self_name - } - }) - } - }) - cls = build.chain({ - base = "setmetatable", - { - "call", - { - cls, - cls_mt - } - } - }) - local value = nil - do - local out_body = { - Run(function(self) - if name then - self:put_name(name) - end - return self:set("super", function(block, chain) - local relative_parent = { - "chain", - cls_name, - { - "dot", - "__parent" - } - } - if not (chain) then - return relative_parent - end - local chain_tail = { - unpack(chain, 3) - } - local head = chain_tail[1] - if head == nil then - return relative_parent - end - local new_chain = relative_parent - local _exp_1 = head[1] - if "call" == _exp_1 then - local calling_name = block:get("current_block") - assert(calling_name, "missing calling name") - chain_tail[1] = { - "call", - { - "self", - unpack(head[2]) - } - } - if ntype(calling_name) == "key_literal" then - insert(new_chain, { - "dot", - calling_name[2] - }) - else - insert(new_chain, { - "index", - calling_name - }) - end - elseif "colon" == _exp_1 then - local call = chain_tail[2] - if call and call[1] == "call" then - chain_tail[1] = { - "dot", - head[2] - } - chain_tail[2] = { - "call", - { - "self", - unpack(call[2]) - } - } - end - end - for _index_0 = 1, #chain_tail do - local item = chain_tail[_index_0] - insert(new_chain, item) - end - return new_chain - end) - end), - { - "declare", - { - cls_name - } - }, - { - "declare_glob", - "*" - }, - parent_val and build.assign_one(parent_cls_name, parent_val) or NOOP, - build.assign_one(base_name, { - "table", - properties - }), - build.assign_one(base_name:chain("__index"), base_name), - parent_val and build.chain({ - base = "setmetatable", - { - "call", - { - base_name, - build.chain({ - base = parent_cls_name, - { - "dot", - "__base" - } - }) - } - } - }) or NOOP, - build.assign_one(cls_name, cls), - build.assign_one(base_name:chain("__class"), cls_name), - build.group((function() - if #statements > 0 then - return { - build.assign_one(LocalName("self"), cls_name), - build.group(statements) - } - end - end)()), - parent_val and build["if"]({ - cond = { - "exp", - parent_cls_name:chain("__inherited") - }, - ["then"] = { - parent_cls_name:chain("__inherited", { - "call", - { - parent_cls_name, - cls_name - } - }) - } - }) or NOOP, - build.group((function() - if name then - return { - build.assign_one(name, cls_name) - } - end - end)()), - (function() - if ret then - return ret(cls_name) - end - end)() - } - value = build.group({ - build.group((function() - if ntype(name) == "value" then - return { - build.declare({ - names = { - name - } - }) - } - end - end)()), - build["do"](out_body) - }) - end - return value - end -}) -do - local _class_0 - local _base_0 = { - body_idx = { - ["for"] = 4, - ["while"] = 3, - foreach = 4 - }, - convert = function(self, node) - local index = self.body_idx[ntype(node)] - node[index] = self:mutate_body(node[index]) - return self:wrap(node) - end, - wrap = function(self, node, group_type) - if group_type == nil then - group_type = "block_exp" - end - return build[group_type]({ - build.assign_one(self.accum_name, build.table()), - build.assign_one(self.len_name, 1), - node, - group_type == "block_exp" and self.accum_name or NOOP - }) - end, - mutate_body = function(self, body) - local single_stm = is_singular(body) - local val - if single_stm and types.is_value(single_stm) then - body = { } - val = single_stm - else - body = transform_last_stm(body, function(n) - if types.is_value(n) then - return build.assign_one(self.value_name, n) - else - return build.group({ - { - "declare", - { - self.value_name - } - }, - n - }) - end - end) - val = self.value_name - end - local update = { - build.assign_one(NameProxy.index(self.accum_name, self.len_name), val), - { - "update", - self.len_name, - "+=", - 1 - } - } - insert(body, build.group(update)) - return body - end - } - _base_0.__index = _base_0 - _class_0 = setmetatable({ - __init = function(self, accum_name) - self.accum_name = NameProxy("accum") - self.value_name = NameProxy("value") - self.len_name = NameProxy("len") - end, - __base = _base_0, - __name = "Accumulator" - }, { - __index = _base_0, - __call = function(cls, ...) - local _self_0 = setmetatable({}, _base_0) - cls.__init(_self_0, ...) - return _self_0 - end - }) - _base_0.__class = _class_0 - Accumulator = _class_0 -end -default_accumulator = function(self, node) - return Accumulator():convert(node) -end -implicitly_return = function(scope) - local is_top = true - local fn - fn = function(stm) - local t = ntype(stm) - if t == "decorated" then - stm = scope.transform.statement(stm) - t = ntype(stm) - end - if types.cascading[t] then - is_top = false - return scope.transform.statement(stm, fn) - elseif types.manual_return[t] or not types.is_value(stm) then - if is_top and t == "return" and stm[2] == "" then - return NOOP - else - return stm - end - else - if t == "comprehension" and not types.comprehension_has_value(stm) then - return stm - else - return { - "return", - stm - } - end - end - end - return fn -end -Value = Transformer({ - ["for"] = default_accumulator, - ["while"] = default_accumulator, - foreach = default_accumulator, - ["do"] = function(self, node) - return build.block_exp(node[2]) - end, - decorated = function(self, node) - return self.transform.statement(node) - end, - class = function(self, node) - return build.block_exp({ - node - }) - end, - string = function(self, node) - local delim = node[2] - local convert_part - convert_part = function(part) - if type(part) == "string" or part == nil then - return { - "string", - delim, - part or "" - } - else - return build.chain({ - base = "tostring", - { - "call", - { - part[2] - } - } - }) - end - end - if #node <= 3 then - if type(node[3]) == "string" then - return node - else - return convert_part(node[3]) - end - end - local e = { - "exp", - convert_part(node[3]) - } - for i = 4, #node do - insert(e, "..") - insert(e, convert_part(node[i])) - end - return e - end, - comprehension = function(self, node) - local a = Accumulator() - node = self.transform.statement(node, function(exp) - return a:mutate_body({ - exp - }) - end) - return a:wrap(node) - end, - tblcomprehension = function(self, node) - local _, explist, clauses = unpack(node) - local key_exp, value_exp = unpack(explist) - local accum = NameProxy("tbl") - local inner - if value_exp then - local dest = build.chain({ - base = accum, - { - "index", - key_exp - } - }) - inner = { - build.assign_one(dest, value_exp) - } - else - local key_name, val_name = NameProxy("key"), NameProxy("val") - local dest = build.chain({ - base = accum, - { - "index", - key_name - } - }) - inner = { - build.assign({ - names = { - key_name, - val_name - }, - values = { - key_exp - } - }), - build.assign_one(dest, val_name) - } - end - return build.block_exp({ - build.assign_one(accum, build.table()), - construct_comprehension(inner, clauses), - accum - }) - end, - fndef = function(self, node) - smart_node(node) - node.body = transform_last_stm(node.body, implicitly_return(self)) - node.body = { - Run(function(self) - return self:listen("varargs", function() end) - end), - unpack(node.body) - } - return node - end, - ["if"] = function(self, node) - return build.block_exp({ - node - }) - end, - unless = function(self, node) - return build.block_exp({ - node - }) - end, - with = function(self, node) - return build.block_exp({ - node - }) - end, - switch = function(self, node) - return build.block_exp({ - node - }) - end, - chain = function(self, node) - for i = 2, #node do - local part = node[i] - if ntype(part) == "dot" and data.lua_keywords[part[2]] then - node[i] = { - "index", - { - "string", - '"', - part[2] - } - } - end - end - if ntype(node[2]) == "string" then - node[2] = { - "parens", - node[2] - } - end - if chain_is_stub(node) then - local base_name = NameProxy("base") - local fn_name = NameProxy("fn") - local colon = table.remove(node) - local is_super = ntype(node[2]) == "ref" and node[2][2] == "super" - return build.block_exp({ - build.assign({ - names = { - base_name - }, - values = { - node - } - }), - build.assign({ - names = { - fn_name - }, - values = { - build.chain({ - base = base_name, - { - "dot", - colon[2] - } - }) - } - }), - build.fndef({ - args = { - { - "..." - } - }, - body = { - build.chain({ - base = fn_name, - { - "call", - { - is_super and "self" or base_name, - "..." - } - } - }) - } - }) - }) - end - end, - block_exp = function(self, node) - local _, body = unpack(node) - local fn = nil - local arg_list = { } - fn = smart_node(build.fndef({ - body = { - Run(function(self) - return self:listen("varargs", function() - insert(arg_list, "...") - insert(fn.args, { - "..." - }) - return self:unlisten("varargs") - end) - end), - unpack(body) - } - })) - return build.chain({ - base = { - "parens", - fn - }, - { - "call", - arg_list - } - }) - end -}) return { - Statement = Statement, - Value = Value, - Run = Run + Statement = require("moonscript.transform.statement"), + Value = require("moonscript.transform.value") } diff --git a/moonscript/transform.moon b/moonscript/transform.moon index 27127d2d..29a93ad2 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -1,977 +1,5 @@ -types = require "moonscript.types" -util = require "moonscript.util" -data = require "moonscript.data" - -import reversed, unpack from util -import ntype, mtype, build, smart_node, is_slice, value_is_singular from types -import insert from table - -import NameProxy, LocalName from require "moonscript.transform.names" -import Run, transform_last_stm, last_stm, chain_is_stub from require "moonscript.transform.statements" - -import Transformer from require "moonscript.transform.transformer" - -destructure = require "moonscript.transform.destructure" -NOOP = {"noop"} - -local * - --- is a body a sindle expression/statement -is_singular = (body) -> - return false if #body != 1 - if "group" == ntype body - is_singular body[2] - else - body[1] - --- this mutates body searching for assigns -extract_declarations = (body=@current_stms, start=@current_stm_i + 1, out={}) => - for i=start,#body - stm = body[i] - continue if stm == nil - stm = @transform.statement stm - body[i] = stm - switch stm[1] - when "assign", "declare" - for name in *stm[2] - if ntype(name) == "ref" - insert out, name - elseif type(name) == "string" - -- TODO: don't use string literal as ref - insert out, name - when "group" - extract_declarations @, stm[2], 1, out - out - -expand_elseif_assign = (ifstm) -> - for i = 4, #ifstm - case = ifstm[i] - if ntype(case) == "elseif" and ntype(case[2]) == "assign" - split = { unpack ifstm, 1, i - 1 } - insert split, { - "else", { - {"if", case[2], case[3], unpack ifstm, i + 1} - } - } - return split - - ifstm - -constructor_name = "new" - -with_continue_listener = (body) -> - continue_name = nil - - { - Run => - @listen "continue", -> - unless continue_name - continue_name = NameProxy"continue" - @put_name continue_name - continue_name - - build.group body - - Run => - return unless continue_name - last = last_stm body - enclose_lines = types.terminating[last and ntype(last)] - - @put_name continue_name, nil - @splice (lines) -> - lines = {"do", {lines}} if enclose_lines - - { - {"assign", {continue_name}, {"false"}} - {"repeat", "true", { - lines - {"assign", {continue_name}, {"true"}} - }} - {"if", {"not", continue_name}, { - {"break"} - }} - } - } - - -construct_comprehension = (inner, clauses) -> - current_stms = inner - for _, clause in reversed clauses - t = clause[1] - 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] - -Statement = Transformer { - transform: (tuple) => - {_, node, fn} = tuple - fn node - - root_stms: (body) => - transform_last_stm body, implicitly_return @ - - return: (node) => - ret_val = node[2] - ret_val_type = ntype ret_val - - if ret_val_type == "explist" and #ret_val == 2 - ret_val = ret_val[2] - ret_val_type = ntype ret_val - - if types.cascading[ret_val_type] - return implicitly_return(@) ret_val - - -- flatten things that create block exp - if ret_val_type == "chain" or ret_val_type == "comprehension" or ret_val_type == "tblcomprehension" - ret_val = Value\transform_once @, ret_val - if ntype(ret_val) == "block_exp" - return build.group transform_last_stm ret_val[2], (stm)-> - {"return", stm} - - node[2] = ret_val - node - - declare_glob: (node) => - names = extract_declarations @ - - if node[2] == "^" - names = for name in *names - continue unless name[2]\match "^%u" - name - - {"declare", names} - - assign: (node) => - names, values = unpack node, 2 - - num_values = #values - num_names = #values - - -- special code simplifications for single assigns - if num_names == 1 and num_values == 1 - first_value = values[1] - first_name = names[1] - first_type = ntype first_value - - -- reduce colon stub chain to block exp - if first_type == "chain" - first_value = Value\transform_once @, first_value - first_type = ntype first_value - - switch ntype first_value - when "block_exp" - block_body = first_value[2] - idx = #block_body - block_body[idx] = build.assign_one first_name, block_body[idx] - - return build.group { - {"declare", {first_name}} - {"do", block_body} - } - - when "comprehension", "tblcomprehension", "foreach", "for", "while" - return build.assign_one first_name, Value\transform_once @, first_value - else - values[1] = first_value - - -- bubble cascading assigns - transformed = if num_values == 1 - value = values[1] - t = ntype value - - if t == "decorated" - value = @transform.statement value - t = ntype value - - if types.cascading[t] - ret = (stm) -> - if types.is_value stm - {"assign", names, {stm}} - else - stm - - build.group { - {"declare", names} - @transform.statement value, ret, node - } - - node = transformed or node - - if destructure.has_destructure names - return destructure.split_assign @, node - - 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 - if #node > 2 - if node[2] == "class" - cls = smart_node node[3] - build.group { - {"export", {cls.name}} - cls - } - else - -- pull out vawlues and assign them after the export - build.group { - { "export", node[2] } - build.assign { - names: node[2] - values: node[3] - } - } - else - nil - - update: (node) => - _, name, op, exp = unpack node - op_final = op\match "^(.+)=$" - error "Unknown op: "..op if not op_final - exp = {"parens", exp} unless value_is_singular exp - build.assign_one name, {"exp", name, op_final, exp} - - import: (node) => - _, names, source = unpack node - table_values = for name in *names - dest_name = if ntype(name) == "colon" - name[2] - else - name - - {{"key_literal", name}, dest_name} - - dest = { "table", table_values } - { "assign", {dest}, {source}, [-1]: node[-1] } - - comprehension: (node, action) => - _, exp, clauses = unpack node - - action = action or (exp) -> {exp} - construct_comprehension action(exp), clauses - - do: (node, ret) => - node[2] = transform_last_stm node[2], ret if ret - node - - decorated: (node) => - stm, dec = unpack node, 2 - - wrapped = switch dec[1] - when "if" - cond, fail = unpack dec, 2 - fail = { "else", { fail } } if fail - { "if", cond, { stm }, fail } - when "unless" - { "unless", dec[2], { stm } } - when "comprehension" - { "comprehension", stm, dec[2] } - else - error "Unknown decorator " .. dec[1] - - if ntype(stm) == "assign" - wrapped = build.group { - build.declare names: [name for name in *stm[2] when ntype(name) == "ref"] - wrapped - } - - wrapped - - unless: (node) => - { "if", {"not", {"parens", node[2]}}, unpack node, 3 } - - if: (node, ret) => - -- expand assign in cond - if ntype(node[2]) == "assign" - _, assign, body = unpack node - if destructure.has_destructure assign[2] - name = NameProxy "des" - - body = { - destructure.build_assign @, assign[2][1], name - build.group node[3] - } - - return build.do { - build.assign_one name, assign[3][1] - {"if", name, body, unpack node, 4} - } - else - name = assign[2][1] - return build["do"] { - assign - {"if", name, unpack node, 3} - } - - node = expand_elseif_assign node - - -- apply cascading return decorator - if ret - smart_node node - -- mutate all the bodies - node['then'] = transform_last_stm node['then'], ret - for i = 4, #node - case = node[i] - body_idx = #node[i] - case[body_idx] = transform_last_stm case[body_idx], ret - - node - - with: (node, ret) => - exp, block = unpack node, 2 - - copy_scope = true - local scope_name, named_assign - - if last = last_stm block - ret = false if types.terminating[ntype(last)] - - if ntype(exp) == "assign" - names, values = unpack exp, 2 - first_name = names[1] - - if ntype(first_name) == "ref" - scope_name = first_name - named_assign = exp - exp = values[1] - copy_scope = false - else - scope_name = NameProxy "with" - exp = values[1] - values[1] = scope_name - named_assign = {"assign", names, values} - - elseif @is_local exp - scope_name = exp - copy_scope = false - - scope_name or= NameProxy "with" - - out = build.do { - copy_scope and build.assign_one(scope_name, exp) or NOOP - named_assign or NOOP - Run => @set "scope_var", scope_name - unpack block - } - - if ret - table.insert out[2], ret scope_name - - out - - foreach: (node, _) => - smart_node node - source = unpack node.iter - - destructures = {} - node.names = for i, name in ipairs node.names - if ntype(name) == "table" - with proxy = NameProxy "des" - insert destructures, destructure.build_assign @, name, proxy - else - name - - if next destructures - insert destructures, build.group node.body - node.body = destructures - - if ntype(source) == "unpack" - list = source[2] - - index_name = NameProxy "index" - - list_name = @is_local(list) and list or NameProxy "list" - - slice_var = nil - bounds = if is_slice list - slice = list[#list] - table.remove list - table.remove slice, 1 - - list_name = list if @is_local list - - slice[2] = if slice[2] and slice[2] != "" - max_tmp_name = NameProxy "max" - slice_var = build.assign_one max_tmp_name, slice[2] - {"exp", max_tmp_name, "<", 0 - "and", {"length", list_name}, "+", max_tmp_name - "or", max_tmp_name } - else - {"length", list_name} - - slice - else - {1, {"length", list_name}} - - return build.group { - list_name != list and build.assign_one(list_name, list) or NOOP - slice_var or NOOP - build["for"] { - name: index_name - bounds: bounds - body: { - {"assign", node.names, { NameProxy.index list_name, index_name }} - build.group node.body - } - } - } - - node.body = with_continue_listener node.body - - while: (node) => - smart_node node - node.body = with_continue_listener node.body - - for: (node) => - smart_node node - node.body = with_continue_listener node.body - - switch: (node, ret) => - _, exp, conds = unpack node - exp_name = NameProxy "exp" - - -- convert switch conds into if statment conds - convert_cond = (cond) -> - t, case_exps, body = unpack cond - out = {} - insert out, t == "case" and "elseif" or "else" - if t != "else" - cond_exp = {} - for i, case in ipairs case_exps - if i == 1 - insert cond_exp, "exp" - else - insert cond_exp, "or" - - case = {"parens", case} unless value_is_singular case - insert cond_exp, {"exp", case, "==", exp_name} - - insert out, cond_exp - else - body = case_exps - - if ret - body = transform_last_stm body, ret - - insert out, body - - out - - first = true - if_stm = {"if"} - for cond in *conds - if_cond = convert_cond cond - if first - first = false - insert if_stm, if_cond[2] - insert if_stm, if_cond[3] - else - insert if_stm, if_cond - - build.group { - build.assign_one exp_name, exp - if_stm - } - - class: (node, ret, parent_assign) => - _, name, parent_val, body = unpack node - parent_val = nil if parent_val == "" - - -- split apart properties and statements - statements = {} - properties = {} - for item in *body - switch item[1] - when "stm" - insert statements, item[2] - when "props" - for tuple in *item[2,] - if ntype(tuple[1]) == "self" - insert statements, build.assign_one unpack tuple - else - insert properties, tuple - - -- find constructor - local constructor - properties = for tuple in *properties - key = tuple[1] - if key[1] == "key_literal" and key[2] == constructor_name - constructor = tuple[2] - continue - else - tuple - - parent_cls_name = NameProxy "parent" - base_name = NameProxy "base" - self_name = NameProxy "self" - cls_name = NameProxy "class" - - unless constructor - constructor = if parent_val - build.fndef { - args: {{"..."}} - arrow: "fat" - body: { - build.chain { base: "super", {"call", {"..."}} } - } - } - else - build.fndef! - - real_name = name or parent_assign and parent_assign[2][1] - real_name = switch ntype real_name - when "chain" - last = real_name[#real_name] - switch ntype last - when "dot" - {"string", '"', last[2]} - when "index" - last[2] - else - "nil" - when "nil" - "nil" - else - name_t = type real_name - -- TODO: don't use string literal as ref - flattened_name = if name_t == "string" - real_name - elseif name_t == "table" and real_name[1] == "ref" - real_name[2] - else - error "don't know how to extract name from #{name_t}" - - {"string", '"', flattened_name} - - cls = build.table { - {"__init", constructor} - {"__base", base_name} - {"__name", real_name} -- "quote the string" - parent_val and {"__parent", parent_cls_name} or nil - } - - -- looking up a name in the class object - class_index = if parent_val - class_lookup = build["if"] { - cond: { "exp", {"ref", "val"}, "==", "nil" } - then: { - build.assign_one LocalName"parent", build.chain { - base: "rawget" - { - "call", { - {"ref", "cls"} - {"string", '"', "__parent"} - } - } - } - - build.if { - cond: LocalName "parent" - then: { - build.chain { - base: LocalName "parent" - {"index", "name"} - } - } - } - } - } - insert class_lookup, {"else", {"val"}} - - build.fndef { - args: {{"cls"}, {"name"}} - body: { - build.assign_one LocalName"val", build.chain { - base: "rawget", {"call", {base_name, {"ref", "name"}}} - } - class_lookup - } - } - else - base_name - - cls_mt = build.table { - {"__index", class_index} - {"__call", build.fndef { - args: {{"cls"}, {"..."}} - body: { - build.assign_one self_name, build.chain { - base: "setmetatable" - {"call", {"{}", base_name}} - } - build.chain { - base: "cls.__init" - {"call", {self_name, "..."}} - } - self_name - } - }} - } - - cls = build.chain { - base: "setmetatable" - {"call", {cls, cls_mt}} - } - - value = nil - with build - out_body = { - Run => - -- make sure we don't assign the class to a local inside the do - @put_name name if name - - @set "super", (block, chain) -> - relative_parent = { - "chain", - cls_name - {"dot", "__parent"} - } - - return relative_parent unless chain - - chain_tail = { unpack chain, 3 } - head = chain_tail[1] - - if head == nil - return relative_parent - - new_chain = relative_parent - - switch head[1] - -- calling super, inject calling name and self into chain - when "call" - calling_name = block\get"current_block" - assert calling_name, "missing calling name" - chain_tail[1] = {"call", {"self", unpack head[2]}} - - if ntype(calling_name) == "key_literal" - insert new_chain, {"dot", calling_name[2]} - else - insert new_chain, {"index", calling_name} - - -- colon call on super, replace class with self as first arg - when "colon" - call = chain_tail[2] - -- calling chain tail - if call and call[1] == "call" - chain_tail[1] = { - "dot" - head[2] - } - - chain_tail[2] = { - "call" - { - "self" - unpack call[2] - } - } - - insert new_chain, item for item in *chain_tail - new_chain - - {"declare", { cls_name }} - {"declare_glob", "*"} - - parent_val and .assign_one(parent_cls_name, parent_val) or NOOP - - .assign_one base_name, {"table", properties} - .assign_one base_name\chain"__index", base_name - - parent_val and .chain({ - base: "setmetatable" - {"call", { - base_name, - .chain { base: parent_cls_name, {"dot", "__base"}} - }} - }) or NOOP - - .assign_one cls_name, cls - .assign_one base_name\chain"__class", cls_name - - .group if #statements > 0 then { - .assign_one LocalName"self", cls_name - .group statements - } - - -- run the inherited callback - parent_val and .if({ - cond: {"exp", parent_cls_name\chain "__inherited" } - then: { - parent_cls_name\chain "__inherited", {"call", { - parent_cls_name, cls_name - }} - } - }) or NOOP - - .group if name then { - .assign_one name, cls_name - } - - if ret - ret cls_name - } - - value = .group { - .group if ntype(name) == "value" then { - .declare names: {name} - } - - .do out_body - } - - value +{ + Statement: require "moonscript.transform.statement" + Value: require "moonscript.transform.value" } - -class Accumulator - body_idx: { for: 4, while: 3, foreach: 4 } - - new: (accum_name) => - @accum_name = NameProxy "accum" - @value_name = NameProxy "value" - @len_name = NameProxy "len" - - -- wraps node and mutates body - convert: (node) => - index = @body_idx[ntype node] - node[index] = @mutate_body node[index] - @wrap node - - -- wrap the node into a block_exp - wrap: (node, group_type="block_exp") => - build[group_type] { - build.assign_one @accum_name, build.table! - build.assign_one @len_name, 1 - node - group_type == "block_exp" and @accum_name or NOOP - } - - -- mutates the body of a loop construct to save last value into accumulator - mutate_body: (body) => - -- shortcut to write simpler code if body is a single expression - single_stm = is_singular body - val = if single_stm and types.is_value single_stm - body = {} - single_stm - else - body = transform_last_stm body, (n) -> - if types.is_value n - build.assign_one @value_name, n - else - -- just ignore it - build.group { - {"declare", {@value_name}} - n - } - @value_name - - update = { - build.assign_one NameProxy.index(@accum_name, @len_name), val - {"update", @len_name, "+=", 1} - } - - insert body, build.group update - body - -default_accumulator = (node) => - Accumulator!\convert node - -implicitly_return = (scope) -> - is_top = true - fn = (stm) -> - t = ntype stm - - -- expand decorated - if t == "decorated" - stm = scope.transform.statement stm - t = ntype stm - - if types.cascading[t] - is_top = false - scope.transform.statement stm, fn - elseif types.manual_return[t] or not types.is_value stm - -- remove blank return statement - if is_top and t == "return" and stm[2] == "" - NOOP - else - stm - else - if t == "comprehension" and not types.comprehension_has_value stm - stm - else - {"return", stm} - - fn - -Value = Transformer { - for: default_accumulator - while: default_accumulator - foreach: default_accumulator - - do: (node) => - build.block_exp node[2] - - decorated: (node) => - @transform.statement node - - class: (node) => - build.block_exp { node } - - string: (node) => - delim = node[2] - - convert_part = (part) -> - if type(part) == "string" or part == nil - {"string", delim, part or ""} - else - build.chain { base: "tostring", {"call", {part[2]}} } - - -- reduced to single item - if #node <= 3 - return if type(node[3]) == "string" - node - else - convert_part node[3] - - e = {"exp", convert_part node[3]} - - for i=4, #node - insert e, ".." - insert e, convert_part node[i] - e - - comprehension: (node) => - a = Accumulator! - node = @transform.statement node, (exp) -> - a\mutate_body {exp} - a\wrap node - - tblcomprehension: (node) => - _, explist, clauses = unpack node - key_exp, value_exp = unpack explist - - accum = NameProxy "tbl" - - inner = if value_exp - dest = build.chain { base: accum, {"index", key_exp} } - { build.assign_one dest, value_exp } - else - -- If we only have single expression then - -- unpack the result into key and value - key_name, val_name = NameProxy"key", NameProxy"val" - dest = build.chain { base: accum, {"index", key_name} } - { - build.assign names: {key_name, val_name}, values: {key_exp} - build.assign_one dest, val_name - } - - build.block_exp { - build.assign_one accum, build.table! - construct_comprehension inner, clauses - accum - } - - fndef: (node) => - smart_node node - node.body = transform_last_stm node.body, implicitly_return self - node.body = { - Run => @listen "varargs", -> -- capture event - unpack node.body - } - - node - - if: (node) => - build.block_exp { node } - - unless: (node) => - build.block_exp { node } - - with: (node) => - build.block_exp { node } - - switch: (node) => - build.block_exp { node } - - -- pull out colon chain - chain: (node) => - -- escape lua keywords used in dot accessors - for i=2,#node - part = node[i] - if ntype(part) == "dot" and data.lua_keywords[part[2]] - node[i] = { "index", {"string", '"', part[2]} } - - if ntype(node[2]) == "string" - -- add parens if callee is raw string - node[2] = {"parens", node[2] } - - if chain_is_stub node - base_name = NameProxy "base" - fn_name = NameProxy "fn" - colon = table.remove node - - is_super = ntype(node[2]) == "ref" and node[2][2] == "super" - build.block_exp { - build.assign { - names: {base_name} - values: {node} - } - - build.assign { - names: {fn_name} - values: { - build.chain { base: base_name, {"dot", colon[2]} } - } - } - - build.fndef { - args: {{"..."}} - body: { - build.chain { - base: fn_name, {"call", {is_super and "self" or base_name, "..."}} - } - } - } - } - - block_exp: (node) => - _, body = unpack node - - fn = nil - arg_list = {} - - fn = smart_node build.fndef body: { - Run => - @listen "varargs", -> - insert arg_list, "..." - insert fn.args, {"..."} - @unlisten "varargs" - - unpack body - } - - build.chain { base: {"parens", fn}, {"call", arg_list} } -} - -{ :Statement, :Value, :Run } diff --git a/moonscript/transform/accumulator.lua b/moonscript/transform/accumulator.lua new file mode 100644 index 00000000..539c65fd --- /dev/null +++ b/moonscript/transform/accumulator.lua @@ -0,0 +1,110 @@ +local types = require("moonscript.types") +local build, ntype, NOOP +build, ntype, NOOP = types.build, types.ntype, types.NOOP +local NameProxy +NameProxy = require("moonscript.transform.names").NameProxy +local insert +insert = table.insert +local is_singular +is_singular = function(body) + if #body ~= 1 then + return false + end + if "group" == ntype(body) then + return is_singular(body[2]) + else + return body[1] + end +end +local transform_last_stm +transform_last_stm = require("moonscript.transform.statements").transform_last_stm +local Accumulator +do + local _class_0 + local _base_0 = { + body_idx = { + ["for"] = 4, + ["while"] = 3, + foreach = 4 + }, + convert = function(self, node) + local index = self.body_idx[ntype(node)] + node[index] = self:mutate_body(node[index]) + return self:wrap(node) + end, + wrap = function(self, node, group_type) + if group_type == nil then + group_type = "block_exp" + end + return build[group_type]({ + build.assign_one(self.accum_name, build.table()), + build.assign_one(self.len_name, 1), + node, + group_type == "block_exp" and self.accum_name or NOOP + }) + end, + mutate_body = function(self, body) + local single_stm = is_singular(body) + local val + if single_stm and types.is_value(single_stm) then + body = { } + val = single_stm + else + body = transform_last_stm(body, function(n) + if types.is_value(n) then + return build.assign_one(self.value_name, n) + else + return build.group({ + { + "declare", + { + self.value_name + } + }, + n + }) + end + end) + val = self.value_name + end + local update = { + build.assign_one(NameProxy.index(self.accum_name, self.len_name), val), + { + "update", + self.len_name, + "+=", + 1 + } + } + insert(body, build.group(update)) + return body + end + } + _base_0.__index = _base_0 + _class_0 = setmetatable({ + __init = function(self, accum_name) + self.accum_name = NameProxy("accum") + self.value_name = NameProxy("value") + self.len_name = NameProxy("len") + end, + __base = _base_0, + __name = "Accumulator" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + Accumulator = _class_0 +end +local default_accumulator +default_accumulator = function(self, node) + return Accumulator():convert(node) +end +return { + Accumulator = Accumulator, + default_accumulator = default_accumulator +} diff --git a/moonscript/transform/accumulator.moon b/moonscript/transform/accumulator.moon new file mode 100644 index 00000000..62ff015c --- /dev/null +++ b/moonscript/transform/accumulator.moon @@ -0,0 +1,71 @@ +types = require "moonscript.types" + +import build, ntype, NOOP from types +import NameProxy from require "moonscript.transform.names" + +import insert from table + +-- is a body a single expression/statement +is_singular = (body) -> + return false if #body != 1 + if "group" == ntype body + is_singular body[2] + else + body[1] + +import transform_last_stm from require "moonscript.transform.statements" + +class Accumulator + body_idx: { for: 4, while: 3, foreach: 4 } + + new: (accum_name) => + @accum_name = NameProxy "accum" + @value_name = NameProxy "value" + @len_name = NameProxy "len" + + -- wraps node and mutates body + convert: (node) => + index = @body_idx[ntype node] + node[index] = @mutate_body node[index] + @wrap node + + -- wrap the node into a block_exp + wrap: (node, group_type="block_exp") => + build[group_type] { + build.assign_one @accum_name, build.table! + build.assign_one @len_name, 1 + node + group_type == "block_exp" and @accum_name or NOOP + } + + -- mutates the body of a loop construct to save last value into accumulator + mutate_body: (body) => + -- shortcut to write simpler code if body is a single expression + single_stm = is_singular body + val = if single_stm and types.is_value single_stm + body = {} + single_stm + else + body = transform_last_stm body, (n) -> + if types.is_value n + build.assign_one @value_name, n + else + -- just ignore it + build.group { + {"declare", {@value_name}} + n + } + @value_name + + update = { + build.assign_one NameProxy.index(@accum_name, @len_name), val + {"update", @len_name, "+=", 1} + } + + insert body, build.group update + body + +default_accumulator = (node) => + Accumulator!\convert node + +{ :Accumulator, :default_accumulator } diff --git a/moonscript/transform/statement.lua b/moonscript/transform/statement.lua new file mode 100644 index 00000000..683fb90c --- /dev/null +++ b/moonscript/transform/statement.lua @@ -0,0 +1,1161 @@ +local Transformer +Transformer = require("moonscript.transform.transformer").Transformer +local NameProxy, LocalName +do + local _obj_0 = require("moonscript.transform.names") + NameProxy, LocalName = _obj_0.NameProxy, _obj_0.LocalName +end +local Run, transform_last_stm, implicitly_return, construct_comprehension, last_stm +do + local _obj_0 = require("moonscript.transform.statements") + Run, transform_last_stm, implicitly_return, construct_comprehension, last_stm = _obj_0.Run, _obj_0.transform_last_stm, _obj_0.implicitly_return, _obj_0.construct_comprehension, _obj_0.last_stm +end +local types = require("moonscript.types") +local build, ntype, is_value, smart_node, value_is_singular, is_slice, NOOP +build, ntype, is_value, smart_node, value_is_singular, is_slice, NOOP = types.build, types.ntype, types.is_value, types.smart_node, types.value_is_singular, types.is_slice, types.NOOP +local insert +insert = table.insert +local destructure = require("moonscript.transform.destructure") +local CONSTRUCTOR_NAME = "new" +local with_continue_listener +with_continue_listener = function(body) + local continue_name = nil + return { + Run(function(self) + return self:listen("continue", function() + if not (continue_name) then + continue_name = NameProxy("continue") + self:put_name(continue_name) + end + return continue_name + end) + end), + build.group(body), + Run(function(self) + if not (continue_name) then + return + end + local last = last_stm(body) + local enclose_lines = types.terminating[last and ntype(last)] + self:put_name(continue_name, nil) + return self:splice(function(lines) + if enclose_lines then + lines = { + "do", + { + lines + } + } + end + return { + { + "assign", + { + continue_name + }, + { + "false" + } + }, + { + "repeat", + "true", + { + lines, + { + "assign", + { + continue_name + }, + { + "true" + } + } + } + }, + { + "if", + { + "not", + continue_name + }, + { + { + "break" + } + } + } + } + end) + end) + } +end +local extract_declarations +extract_declarations = function(self, body, start, out) + if body == nil then + body = self.current_stms + end + if start == nil then + start = self.current_stm_i + 1 + end + if out == nil then + out = { } + end + for i = start, #body do + local _continue_0 = false + repeat + local stm = body[i] + if stm == nil then + _continue_0 = true + break + end + stm = self.transform.statement(stm) + body[i] = stm + local _exp_0 = stm[1] + if "assign" == _exp_0 or "declare" == _exp_0 then + local _list_0 = stm[2] + for _index_0 = 1, #_list_0 do + local name = _list_0[_index_0] + if ntype(name) == "ref" then + insert(out, name) + elseif type(name) == "string" then + insert(out, name) + end + end + elseif "group" == _exp_0 then + extract_declarations(self, stm[2], 1, out) + end + _continue_0 = true + until true + if not _continue_0 then + break + end + end + return out +end +local expand_elseif_assign +expand_elseif_assign = function(ifstm) + for i = 4, #ifstm do + local case = ifstm[i] + if ntype(case) == "elseif" and ntype(case[2]) == "assign" then + local split = { + unpack(ifstm, 1, i - 1) + } + insert(split, { + "else", + { + { + "if", + case[2], + case[3], + unpack(ifstm, i + 1) + } + } + }) + return split + end + end + return ifstm +end +return Transformer({ + transform = function(self, tuple) + local _, node, fn + _, node, fn = tuple[1], tuple[2], tuple[3] + return fn(node) + end, + root_stms = function(self, body) + return transform_last_stm(body, implicitly_return(self)) + end, + ["return"] = function(self, node) + local ret_val = node[2] + local ret_val_type = ntype(ret_val) + if ret_val_type == "explist" and #ret_val == 2 then + ret_val = ret_val[2] + ret_val_type = ntype(ret_val) + end + if types.cascading[ret_val_type] then + return implicitly_return(self)(ret_val) + end + if ret_val_type == "chain" or ret_val_type == "comprehension" or ret_val_type == "tblcomprehension" then + local Value = require("moonscript.transform.value") + ret_val = Value:transform_once(self, ret_val) + if ntype(ret_val) == "block_exp" then + return build.group(transform_last_stm(ret_val[2], function(stm) + return { + "return", + stm + } + end)) + end + end + node[2] = ret_val + return node + end, + declare_glob = function(self, node) + local names = extract_declarations(self) + if node[2] == "^" then + do + local _accum_0 = { } + local _len_0 = 1 + for _index_0 = 1, #names do + local _continue_0 = false + repeat + local name = names[_index_0] + if not (name[2]:match("^%u")) then + _continue_0 = true + break + end + local _value_0 = name + _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 + _continue_0 = true + until true + if not _continue_0 then + break + end + end + names = _accum_0 + end + end + return { + "declare", + names + } + end, + assign = function(self, node) + local names, values = unpack(node, 2) + local num_values = #values + local num_names = #values + if num_names == 1 and num_values == 1 then + local first_value = values[1] + local first_name = names[1] + local first_type = ntype(first_value) + if first_type == "chain" then + local Value = require("moonscript.transform.value") + first_value = Value:transform_once(self, first_value) + first_type = ntype(first_value) + end + local _exp_0 = ntype(first_value) + if "block_exp" == _exp_0 then + local block_body = first_value[2] + local idx = #block_body + block_body[idx] = build.assign_one(first_name, block_body[idx]) + return build.group({ + { + "declare", + { + first_name + } + }, + { + "do", + block_body + } + }) + elseif "comprehension" == _exp_0 or "tblcomprehension" == _exp_0 or "foreach" == _exp_0 or "for" == _exp_0 or "while" == _exp_0 then + local Value = require("moonscript.transform.value") + return build.assign_one(first_name, Value:transform_once(self, first_value)) + else + values[1] = first_value + end + end + local transformed + if num_values == 1 then + local value = values[1] + local t = ntype(value) + if t == "decorated" then + value = self.transform.statement(value) + t = ntype(value) + end + if types.cascading[t] then + local ret + ret = function(stm) + if is_value(stm) then + return { + "assign", + names, + { + stm + } + } + else + return stm + end + end + transformed = build.group({ + { + "declare", + names + }, + self.transform.statement(value, ret, node) + }) + end + end + node = transformed or node + if destructure.has_destructure(names) then + return destructure.split_assign(self, node) + end + return 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 + local cls = smart_node(node[3]) + return build.group({ + { + "export", + { + cls.name + } + }, + cls + }) + else + return build.group({ + { + "export", + node[2] + }, + build.assign({ + names = node[2], + values = node[3] + }) + }) + end + else + return nil + end + end, + update = function(self, node) + local _, name, op, exp = unpack(node) + local op_final = op:match("^(.+)=$") + if not op_final then + error("Unknown op: " .. op) + end + if not (value_is_singular(exp)) then + exp = { + "parens", + exp + } + end + return build.assign_one(name, { + "exp", + name, + op_final, + exp + }) + end, + import = function(self, node) + local _, names, source = unpack(node) + local table_values + do + local _accum_0 = { } + local _len_0 = 1 + for _index_0 = 1, #names do + local name = names[_index_0] + local dest_name + if ntype(name) == "colon" then + dest_name = name[2] + else + dest_name = name + end + local _value_0 = { + { + "key_literal", + name + }, + dest_name + } + _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 + end + table_values = _accum_0 + end + local dest = { + "table", + table_values + } + return { + "assign", + { + dest + }, + { + source + }, + [-1] = node[-1] + } + end, + comprehension = function(self, node, action) + local _, exp, clauses = unpack(node) + action = action or function(exp) + return { + exp + } + end + return construct_comprehension(action(exp), clauses) + end, + ["do"] = function(self, node, ret) + if ret then + node[2] = transform_last_stm(node[2], ret) + end + return node + end, + decorated = function(self, node) + local stm, dec = unpack(node, 2) + local wrapped + local _exp_0 = dec[1] + if "if" == _exp_0 then + local cond, fail = unpack(dec, 2) + if fail then + fail = { + "else", + { + fail + } + } + end + wrapped = { + "if", + cond, + { + stm + }, + fail + } + elseif "unless" == _exp_0 then + wrapped = { + "unless", + dec[2], + { + stm + } + } + elseif "comprehension" == _exp_0 then + wrapped = { + "comprehension", + stm, + dec[2] + } + else + wrapped = error("Unknown decorator " .. dec[1]) + end + if ntype(stm) == "assign" then + wrapped = build.group({ + build.declare({ + names = (function() + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = stm[2] + for _index_0 = 1, #_list_0 do + local name = _list_0[_index_0] + if ntype(name) == "ref" then + _accum_0[_len_0] = name + _len_0 = _len_0 + 1 + end + end + return _accum_0 + end)() + }), + wrapped + }) + end + return wrapped + end, + unless = function(self, node) + return { + "if", + { + "not", + { + "parens", + node[2] + } + }, + unpack(node, 3) + } + end, + ["if"] = function(self, node, ret) + if ntype(node[2]) == "assign" then + local _, assign, body = unpack(node) + if destructure.has_destructure(assign[2]) then + local name = NameProxy("des") + body = { + destructure.build_assign(self, assign[2][1], name), + build.group(node[3]) + } + return build["do"]({ + build.assign_one(name, assign[3][1]), + { + "if", + name, + body, + unpack(node, 4) + } + }) + else + local name = assign[2][1] + return build["do"]({ + assign, + { + "if", + name, + unpack(node, 3) + } + }) + end + end + node = expand_elseif_assign(node) + if ret then + smart_node(node) + node['then'] = transform_last_stm(node['then'], ret) + for i = 4, #node do + local case = node[i] + local body_idx = #node[i] + case[body_idx] = transform_last_stm(case[body_idx], ret) + end + end + return node + end, + with = function(self, node, ret) + local exp, block = unpack(node, 2) + local copy_scope = true + local scope_name, named_assign + do + local last = last_stm(block) + if last then + if types.terminating[ntype(last)] then + ret = false + end + end + end + if ntype(exp) == "assign" then + local names, values = unpack(exp, 2) + local first_name = names[1] + if ntype(first_name) == "ref" then + scope_name = first_name + named_assign = exp + exp = values[1] + copy_scope = false + else + scope_name = NameProxy("with") + exp = values[1] + values[1] = scope_name + named_assign = { + "assign", + names, + values + } + end + elseif self:is_local(exp) then + scope_name = exp + copy_scope = false + end + scope_name = scope_name or NameProxy("with") + local out = build["do"]({ + copy_scope and build.assign_one(scope_name, exp) or NOOP, + named_assign or NOOP, + Run(function(self) + return self:set("scope_var", scope_name) + end), + unpack(block) + }) + if ret then + table.insert(out[2], ret(scope_name)) + end + return out + end, + foreach = function(self, node, _) + smart_node(node) + local source = unpack(node.iter) + local destructures = { } + do + local _accum_0 = { } + local _len_0 = 1 + for i, name in ipairs(node.names) do + if ntype(name) == "table" then + do + local proxy = NameProxy("des") + insert(destructures, destructure.build_assign(self, name, proxy)) + _accum_0[_len_0] = proxy + end + else + _accum_0[_len_0] = name + end + _len_0 = _len_0 + 1 + end + node.names = _accum_0 + end + if next(destructures) then + insert(destructures, build.group(node.body)) + node.body = destructures + end + if ntype(source) == "unpack" then + local list = source[2] + local index_name = NameProxy("index") + local list_name = self:is_local(list) and list or NameProxy("list") + local slice_var = nil + local bounds + if is_slice(list) then + local slice = list[#list] + table.remove(list) + table.remove(slice, 1) + if self:is_local(list) then + list_name = list + end + if slice[2] and slice[2] ~= "" then + local max_tmp_name = NameProxy("max") + slice_var = build.assign_one(max_tmp_name, slice[2]) + slice[2] = { + "exp", + max_tmp_name, + "<", + 0, + "and", + { + "length", + list_name + }, + "+", + max_tmp_name, + "or", + max_tmp_name + } + else + slice[2] = { + "length", + list_name + } + end + bounds = slice + else + bounds = { + 1, + { + "length", + list_name + } + } + end + return build.group({ + list_name ~= list and build.assign_one(list_name, list) or NOOP, + slice_var or NOOP, + build["for"]({ + name = index_name, + bounds = bounds, + body = { + { + "assign", + node.names, + { + NameProxy.index(list_name, index_name) + } + }, + build.group(node.body) + } + }) + }) + end + node.body = with_continue_listener(node.body) + end, + ["while"] = function(self, node) + smart_node(node) + node.body = with_continue_listener(node.body) + end, + ["for"] = function(self, node) + smart_node(node) + node.body = with_continue_listener(node.body) + end, + switch = function(self, node, ret) + local _, exp, conds = unpack(node) + local exp_name = NameProxy("exp") + local convert_cond + convert_cond = function(cond) + local t, case_exps, body = unpack(cond) + local out = { } + insert(out, t == "case" and "elseif" or "else") + if t ~= "else" then + local cond_exp = { } + for i, case in ipairs(case_exps) do + if i == 1 then + insert(cond_exp, "exp") + else + insert(cond_exp, "or") + end + if not (value_is_singular(case)) then + case = { + "parens", + case + } + end + insert(cond_exp, { + "exp", + case, + "==", + exp_name + }) + end + insert(out, cond_exp) + else + body = case_exps + end + if ret then + body = transform_last_stm(body, ret) + end + insert(out, body) + return out + end + local first = true + local if_stm = { + "if" + } + for _index_0 = 1, #conds do + local cond = conds[_index_0] + local if_cond = convert_cond(cond) + if first then + first = false + insert(if_stm, if_cond[2]) + insert(if_stm, if_cond[3]) + else + insert(if_stm, if_cond) + end + end + return build.group({ + build.assign_one(exp_name, exp), + if_stm + }) + end, + class = function(self, node, ret, parent_assign) + local _, name, parent_val, body = unpack(node) + if parent_val == "" then + parent_val = nil + end + local statements = { } + local properties = { } + for _index_0 = 1, #body do + local item = body[_index_0] + local _exp_0 = item[1] + if "stm" == _exp_0 then + insert(statements, item[2]) + elseif "props" == _exp_0 then + for _index_1 = 2, #item do + local tuple = item[_index_1] + if ntype(tuple[1]) == "self" then + insert(statements, build.assign_one(unpack(tuple))) + else + insert(properties, tuple) + end + end + end + end + local constructor + do + local _accum_0 = { } + local _len_0 = 1 + for _index_0 = 1, #properties do + local _continue_0 = false + repeat + local tuple = properties[_index_0] + local key = tuple[1] + local _value_0 + if key[1] == "key_literal" and key[2] == CONSTRUCTOR_NAME then + constructor = tuple[2] + _continue_0 = true + break + else + _value_0 = tuple + end + _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 + _continue_0 = true + until true + if not _continue_0 then + break + end + end + properties = _accum_0 + end + local parent_cls_name = NameProxy("parent") + local base_name = NameProxy("base") + local self_name = NameProxy("self") + local cls_name = NameProxy("class") + if not (constructor) then + if parent_val then + constructor = build.fndef({ + args = { + { + "..." + } + }, + arrow = "fat", + body = { + build.chain({ + base = "super", + { + "call", + { + "..." + } + } + }) + } + }) + else + constructor = build.fndef() + end + end + local real_name = name or parent_assign and parent_assign[2][1] + local _exp_0 = ntype(real_name) + if "chain" == _exp_0 then + local last = real_name[#real_name] + local _exp_1 = ntype(last) + if "dot" == _exp_1 then + real_name = { + "string", + '"', + last[2] + } + elseif "index" == _exp_1 then + real_name = last[2] + else + real_name = "nil" + end + elseif "nil" == _exp_0 then + real_name = "nil" + else + local name_t = type(real_name) + local flattened_name + if name_t == "string" then + flattened_name = real_name + elseif name_t == "table" and real_name[1] == "ref" then + flattened_name = real_name[2] + else + flattened_name = error("don't know how to extract name from " .. tostring(name_t)) + end + real_name = { + "string", + '"', + flattened_name + } + end + local cls = build.table({ + { + "__init", + constructor + }, + { + "__base", + base_name + }, + { + "__name", + real_name + }, + parent_val and { + "__parent", + parent_cls_name + } or nil + }) + local class_index + if parent_val then + local class_lookup = build["if"]({ + cond = { + "exp", + { + "ref", + "val" + }, + "==", + "nil" + }, + ["then"] = { + build.assign_one(LocalName("parent"), build.chain({ + base = "rawget", + { + "call", + { + { + "ref", + "cls" + }, + { + "string", + '"', + "__parent" + } + } + } + })), + build["if"]({ + cond = LocalName("parent"), + ["then"] = { + build.chain({ + base = LocalName("parent"), + { + "index", + "name" + } + }) + } + }) + } + }) + insert(class_lookup, { + "else", + { + "val" + } + }) + class_index = build.fndef({ + args = { + { + "cls" + }, + { + "name" + } + }, + body = { + build.assign_one(LocalName("val"), build.chain({ + base = "rawget", + { + "call", + { + base_name, + { + "ref", + "name" + } + } + } + })), + class_lookup + } + }) + else + class_index = base_name + end + local cls_mt = build.table({ + { + "__index", + class_index + }, + { + "__call", + build.fndef({ + args = { + { + "cls" + }, + { + "..." + } + }, + body = { + build.assign_one(self_name, build.chain({ + base = "setmetatable", + { + "call", + { + "{}", + base_name + } + } + })), + build.chain({ + base = "cls.__init", + { + "call", + { + self_name, + "..." + } + } + }), + self_name + } + }) + } + }) + cls = build.chain({ + base = "setmetatable", + { + "call", + { + cls, + cls_mt + } + } + }) + local value = nil + do + local out_body = { + Run(function(self) + if name then + self:put_name(name) + end + return self:set("super", function(block, chain) + local relative_parent = { + "chain", + cls_name, + { + "dot", + "__parent" + } + } + if not (chain) then + return relative_parent + end + local chain_tail = { + unpack(chain, 3) + } + local head = chain_tail[1] + if head == nil then + return relative_parent + end + local new_chain = relative_parent + local _exp_1 = head[1] + if "call" == _exp_1 then + local calling_name = block:get("current_block") + assert(calling_name, "missing calling name") + chain_tail[1] = { + "call", + { + "self", + unpack(head[2]) + } + } + if ntype(calling_name) == "key_literal" then + insert(new_chain, { + "dot", + calling_name[2] + }) + else + insert(new_chain, { + "index", + calling_name + }) + end + elseif "colon" == _exp_1 then + local call = chain_tail[2] + if call and call[1] == "call" then + chain_tail[1] = { + "dot", + head[2] + } + chain_tail[2] = { + "call", + { + "self", + unpack(call[2]) + } + } + end + end + for _index_0 = 1, #chain_tail do + local item = chain_tail[_index_0] + insert(new_chain, item) + end + return new_chain + end) + end), + { + "declare", + { + cls_name + } + }, + { + "declare_glob", + "*" + }, + parent_val and build.assign_one(parent_cls_name, parent_val) or NOOP, + build.assign_one(base_name, { + "table", + properties + }), + build.assign_one(base_name:chain("__index"), base_name), + parent_val and build.chain({ + base = "setmetatable", + { + "call", + { + base_name, + build.chain({ + base = parent_cls_name, + { + "dot", + "__base" + } + }) + } + } + }) or NOOP, + build.assign_one(cls_name, cls), + build.assign_one(base_name:chain("__class"), cls_name), + build.group((function() + if #statements > 0 then + return { + build.assign_one(LocalName("self"), cls_name), + build.group(statements) + } + end + end)()), + parent_val and build["if"]({ + cond = { + "exp", + parent_cls_name:chain("__inherited") + }, + ["then"] = { + parent_cls_name:chain("__inherited", { + "call", + { + parent_cls_name, + cls_name + } + }) + } + }) or NOOP, + build.group((function() + if name then + return { + build.assign_one(name, cls_name) + } + end + end)()), + (function() + if ret then + return ret(cls_name) + end + end)() + } + value = build.group({ + build.group((function() + if ntype(name) == "value" then + return { + build.declare({ + names = { + name + } + }) + } + end + end)()), + build["do"](out_body) + }) + end + return value + end +}) diff --git a/moonscript/transform/statement.moon b/moonscript/transform/statement.moon new file mode 100644 index 00000000..646403f9 --- /dev/null +++ b/moonscript/transform/statement.moon @@ -0,0 +1,720 @@ +import Transformer from require "moonscript.transform.transformer" + +import NameProxy, LocalName from require "moonscript.transform.names" + +import Run, transform_last_stm, implicitly_return, construct_comprehension, + last_stm from require "moonscript.transform.statements" + +types = require "moonscript.types" + +import build, ntype, is_value, smart_node, value_is_singular, is_slice, NOOP + from types + +import insert from table + +destructure = require "moonscript.transform.destructure" + +CONSTRUCTOR_NAME = "new" + +with_continue_listener = (body) -> + continue_name = nil + + { + Run => + @listen "continue", -> + unless continue_name + continue_name = NameProxy"continue" + @put_name continue_name + continue_name + + build.group body + + Run => + return unless continue_name + last = last_stm body + enclose_lines = types.terminating[last and ntype(last)] + + @put_name continue_name, nil + @splice (lines) -> + lines = {"do", {lines}} if enclose_lines + + { + {"assign", {continue_name}, {"false"}} + {"repeat", "true", { + lines + {"assign", {continue_name}, {"true"}} + }} + {"if", {"not", continue_name}, { + {"break"} + }} + } + } + + +-- this mutates body searching for assigns +extract_declarations = (body=@current_stms, start=@current_stm_i + 1, out={}) => + for i=start,#body + stm = body[i] + continue if stm == nil + stm = @transform.statement stm + body[i] = stm + switch stm[1] + when "assign", "declare" + for name in *stm[2] + if ntype(name) == "ref" + insert out, name + elseif type(name) == "string" + -- TODO: don't use string literal as ref + insert out, name + when "group" + extract_declarations @, stm[2], 1, out + out + +expand_elseif_assign = (ifstm) -> + for i = 4, #ifstm + case = ifstm[i] + if ntype(case) == "elseif" and ntype(case[2]) == "assign" + split = { unpack ifstm, 1, i - 1 } + insert split, { + "else", { + {"if", case[2], case[3], unpack ifstm, i + 1} + } + } + return split + + ifstm + + +Transformer { + transform: (tuple) => + {_, node, fn} = tuple + fn node + + root_stms: (body) => + transform_last_stm body, implicitly_return @ + + return: (node) => + ret_val = node[2] + ret_val_type = ntype ret_val + + if ret_val_type == "explist" and #ret_val == 2 + ret_val = ret_val[2] + ret_val_type = ntype ret_val + + if types.cascading[ret_val_type] + return implicitly_return(@) ret_val + + -- flatten things that create block exp + if ret_val_type == "chain" or ret_val_type == "comprehension" or ret_val_type == "tblcomprehension" + -- TODO: clean this up + Value = require "moonscript.transform.value" + ret_val = Value\transform_once @, ret_val + if ntype(ret_val) == "block_exp" + return build.group transform_last_stm ret_val[2], (stm)-> + {"return", stm} + + node[2] = ret_val + node + + declare_glob: (node) => + names = extract_declarations @ + + if node[2] == "^" + names = for name in *names + continue unless name[2]\match "^%u" + name + + {"declare", names} + + assign: (node) => + names, values = unpack node, 2 + + num_values = #values + num_names = #values + + -- special code simplifications for single assigns + if num_names == 1 and num_values == 1 + first_value = values[1] + first_name = names[1] + first_type = ntype first_value + + -- reduce colon stub chain to block exp + if first_type == "chain" + -- TODO: clean this up + Value = require "moonscript.transform.value" + first_value = Value\transform_once @, first_value + first_type = ntype first_value + + switch ntype first_value + when "block_exp" + block_body = first_value[2] + idx = #block_body + block_body[idx] = build.assign_one first_name, block_body[idx] + + return build.group { + {"declare", {first_name}} + {"do", block_body} + } + + when "comprehension", "tblcomprehension", "foreach", "for", "while" + -- TODO: clean this up + Value = require "moonscript.transform.value" + return build.assign_one first_name, Value\transform_once @, first_value + else + values[1] = first_value + + -- bubble cascading assigns + transformed = if num_values == 1 + value = values[1] + t = ntype value + + if t == "decorated" + value = @transform.statement value + t = ntype value + + if types.cascading[t] + ret = (stm) -> + if is_value stm + {"assign", names, {stm}} + else + stm + + build.group { + {"declare", names} + @transform.statement value, ret, node + } + + node = transformed or node + + if destructure.has_destructure names + return destructure.split_assign @, node + + 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 + if #node > 2 + if node[2] == "class" + cls = smart_node node[3] + build.group { + {"export", {cls.name}} + cls + } + else + -- pull out vawlues and assign them after the export + build.group { + { "export", node[2] } + build.assign { + names: node[2] + values: node[3] + } + } + else + nil + + update: (node) => + _, name, op, exp = unpack node + op_final = op\match "^(.+)=$" + error "Unknown op: "..op if not op_final + exp = {"parens", exp} unless value_is_singular exp + build.assign_one name, {"exp", name, op_final, exp} + + import: (node) => + _, names, source = unpack node + table_values = for name in *names + dest_name = if ntype(name) == "colon" + name[2] + else + name + + {{"key_literal", name}, dest_name} + + dest = { "table", table_values } + { "assign", {dest}, {source}, [-1]: node[-1] } + + comprehension: (node, action) => + _, exp, clauses = unpack node + + action = action or (exp) -> {exp} + construct_comprehension action(exp), clauses + + do: (node, ret) => + node[2] = transform_last_stm node[2], ret if ret + node + + decorated: (node) => + stm, dec = unpack node, 2 + + wrapped = switch dec[1] + when "if" + cond, fail = unpack dec, 2 + fail = { "else", { fail } } if fail + { "if", cond, { stm }, fail } + when "unless" + { "unless", dec[2], { stm } } + when "comprehension" + { "comprehension", stm, dec[2] } + else + error "Unknown decorator " .. dec[1] + + if ntype(stm) == "assign" + wrapped = build.group { + build.declare names: [name for name in *stm[2] when ntype(name) == "ref"] + wrapped + } + + wrapped + + unless: (node) => + { "if", {"not", {"parens", node[2]}}, unpack node, 3 } + + if: (node, ret) => + -- expand assign in cond + if ntype(node[2]) == "assign" + _, assign, body = unpack node + if destructure.has_destructure assign[2] + name = NameProxy "des" + + body = { + destructure.build_assign @, assign[2][1], name + build.group node[3] + } + + return build.do { + build.assign_one name, assign[3][1] + {"if", name, body, unpack node, 4} + } + else + name = assign[2][1] + return build["do"] { + assign + {"if", name, unpack node, 3} + } + + node = expand_elseif_assign node + + -- apply cascading return decorator + if ret + smart_node node + -- mutate all the bodies + node['then'] = transform_last_stm node['then'], ret + for i = 4, #node + case = node[i] + body_idx = #node[i] + case[body_idx] = transform_last_stm case[body_idx], ret + + node + + with: (node, ret) => + exp, block = unpack node, 2 + + copy_scope = true + local scope_name, named_assign + + if last = last_stm block + ret = false if types.terminating[ntype(last)] + + if ntype(exp) == "assign" + names, values = unpack exp, 2 + first_name = names[1] + + if ntype(first_name) == "ref" + scope_name = first_name + named_assign = exp + exp = values[1] + copy_scope = false + else + scope_name = NameProxy "with" + exp = values[1] + values[1] = scope_name + named_assign = {"assign", names, values} + + elseif @is_local exp + scope_name = exp + copy_scope = false + + scope_name or= NameProxy "with" + + out = build.do { + copy_scope and build.assign_one(scope_name, exp) or NOOP + named_assign or NOOP + Run => @set "scope_var", scope_name + unpack block + } + + if ret + table.insert out[2], ret scope_name + + out + + foreach: (node, _) => + smart_node node + source = unpack node.iter + + destructures = {} + node.names = for i, name in ipairs node.names + if ntype(name) == "table" + with proxy = NameProxy "des" + insert destructures, destructure.build_assign @, name, proxy + else + name + + if next destructures + insert destructures, build.group node.body + node.body = destructures + + if ntype(source) == "unpack" + list = source[2] + + index_name = NameProxy "index" + + list_name = @is_local(list) and list or NameProxy "list" + + slice_var = nil + bounds = if is_slice list + slice = list[#list] + table.remove list + table.remove slice, 1 + + list_name = list if @is_local list + + slice[2] = if slice[2] and slice[2] != "" + max_tmp_name = NameProxy "max" + slice_var = build.assign_one max_tmp_name, slice[2] + {"exp", max_tmp_name, "<", 0 + "and", {"length", list_name}, "+", max_tmp_name + "or", max_tmp_name } + else + {"length", list_name} + + slice + else + {1, {"length", list_name}} + + return build.group { + list_name != list and build.assign_one(list_name, list) or NOOP + slice_var or NOOP + build["for"] { + name: index_name + bounds: bounds + body: { + {"assign", node.names, { NameProxy.index list_name, index_name }} + build.group node.body + } + } + } + + node.body = with_continue_listener node.body + + while: (node) => + smart_node node + node.body = with_continue_listener node.body + + for: (node) => + smart_node node + node.body = with_continue_listener node.body + + switch: (node, ret) => + _, exp, conds = unpack node + exp_name = NameProxy "exp" + + -- convert switch conds into if statment conds + convert_cond = (cond) -> + t, case_exps, body = unpack cond + out = {} + insert out, t == "case" and "elseif" or "else" + if t != "else" + cond_exp = {} + for i, case in ipairs case_exps + if i == 1 + insert cond_exp, "exp" + else + insert cond_exp, "or" + + case = {"parens", case} unless value_is_singular case + insert cond_exp, {"exp", case, "==", exp_name} + + insert out, cond_exp + else + body = case_exps + + if ret + body = transform_last_stm body, ret + + insert out, body + + out + + first = true + if_stm = {"if"} + for cond in *conds + if_cond = convert_cond cond + if first + first = false + insert if_stm, if_cond[2] + insert if_stm, if_cond[3] + else + insert if_stm, if_cond + + build.group { + build.assign_one exp_name, exp + if_stm + } + + class: (node, ret, parent_assign) => + _, name, parent_val, body = unpack node + parent_val = nil if parent_val == "" + + -- split apart properties and statements + statements = {} + properties = {} + for item in *body + switch item[1] + when "stm" + insert statements, item[2] + when "props" + for tuple in *item[2,] + if ntype(tuple[1]) == "self" + insert statements, build.assign_one unpack tuple + else + insert properties, tuple + + -- find constructor + local constructor + properties = for tuple in *properties + key = tuple[1] + if key[1] == "key_literal" and key[2] == CONSTRUCTOR_NAME + constructor = tuple[2] + continue + else + tuple + + parent_cls_name = NameProxy "parent" + base_name = NameProxy "base" + self_name = NameProxy "self" + cls_name = NameProxy "class" + + unless constructor + constructor = if parent_val + build.fndef { + args: {{"..."}} + arrow: "fat" + body: { + build.chain { base: "super", {"call", {"..."}} } + } + } + else + build.fndef! + + real_name = name or parent_assign and parent_assign[2][1] + real_name = switch ntype real_name + when "chain" + last = real_name[#real_name] + switch ntype last + when "dot" + {"string", '"', last[2]} + when "index" + last[2] + else + "nil" + when "nil" + "nil" + else + name_t = type real_name + -- TODO: don't use string literal as ref + flattened_name = if name_t == "string" + real_name + elseif name_t == "table" and real_name[1] == "ref" + real_name[2] + else + error "don't know how to extract name from #{name_t}" + + {"string", '"', flattened_name} + + cls = build.table { + {"__init", constructor} + {"__base", base_name} + {"__name", real_name} -- "quote the string" + parent_val and {"__parent", parent_cls_name} or nil + } + + -- looking up a name in the class object + class_index = if parent_val + class_lookup = build["if"] { + cond: { "exp", {"ref", "val"}, "==", "nil" } + then: { + build.assign_one LocalName"parent", build.chain { + base: "rawget" + { + "call", { + {"ref", "cls"} + {"string", '"', "__parent"} + } + } + } + + build.if { + cond: LocalName "parent" + then: { + build.chain { + base: LocalName "parent" + {"index", "name"} + } + } + } + } + } + insert class_lookup, {"else", {"val"}} + + build.fndef { + args: {{"cls"}, {"name"}} + body: { + build.assign_one LocalName"val", build.chain { + base: "rawget", {"call", {base_name, {"ref", "name"}}} + } + class_lookup + } + } + else + base_name + + cls_mt = build.table { + {"__index", class_index} + {"__call", build.fndef { + args: {{"cls"}, {"..."}} + body: { + build.assign_one self_name, build.chain { + base: "setmetatable" + {"call", {"{}", base_name}} + } + build.chain { + base: "cls.__init" + {"call", {self_name, "..."}} + } + self_name + } + }} + } + + cls = build.chain { + base: "setmetatable" + {"call", {cls, cls_mt}} + } + + value = nil + with build + out_body = { + Run => + -- make sure we don't assign the class to a local inside the do + @put_name name if name + + @set "super", (block, chain) -> + relative_parent = { + "chain", + cls_name + {"dot", "__parent"} + } + + return relative_parent unless chain + + chain_tail = { unpack chain, 3 } + head = chain_tail[1] + + if head == nil + return relative_parent + + new_chain = relative_parent + + switch head[1] + -- calling super, inject calling name and self into chain + when "call" + calling_name = block\get"current_block" + assert calling_name, "missing calling name" + chain_tail[1] = {"call", {"self", unpack head[2]}} + + if ntype(calling_name) == "key_literal" + insert new_chain, {"dot", calling_name[2]} + else + insert new_chain, {"index", calling_name} + + -- colon call on super, replace class with self as first arg + when "colon" + call = chain_tail[2] + -- calling chain tail + if call and call[1] == "call" + chain_tail[1] = { + "dot" + head[2] + } + + chain_tail[2] = { + "call" + { + "self" + unpack call[2] + } + } + + insert new_chain, item for item in *chain_tail + new_chain + + {"declare", { cls_name }} + {"declare_glob", "*"} + + parent_val and .assign_one(parent_cls_name, parent_val) or NOOP + + .assign_one base_name, {"table", properties} + .assign_one base_name\chain"__index", base_name + + parent_val and .chain({ + base: "setmetatable" + {"call", { + base_name, + .chain { base: parent_cls_name, {"dot", "__base"}} + }} + }) or NOOP + + .assign_one cls_name, cls + .assign_one base_name\chain"__class", cls_name + + .group if #statements > 0 then { + .assign_one LocalName"self", cls_name + .group statements + } + + -- run the inherited callback + parent_val and .if({ + cond: {"exp", parent_cls_name\chain "__inherited" } + then: { + parent_cls_name\chain "__inherited", {"call", { + parent_cls_name, cls_name + }} + } + }) or NOOP + + .group if name then { + .assign_one name, cls_name + } + + if ret + ret cls_name + } + + value = .group { + .group if ntype(name) == "value" then { + .declare names: {name} + } + + .do out_body + } + + value +} diff --git a/moonscript/transform/statements.lua b/moonscript/transform/statements.lua index 994df895..dc562a5d 100644 --- a/moonscript/transform/statements.lua +++ b/moonscript/transform/statements.lua @@ -1,8 +1,6 @@ -local ntype, mtype -do - local _obj_0 = require("moonscript.types") - ntype, mtype = _obj_0.ntype, _obj_0.mtype -end +local types = require("moonscript.types") +local ntype, mtype, is_value, NOOP +ntype, mtype, is_value, NOOP = types.ntype, types.mtype, types.is_value, types.NOOP local Run do local _class_0 @@ -74,9 +72,88 @@ chain_is_stub = function(chain) local stub = chain[#chain] return stub and ntype(stub) == "colon" end +local implicitly_return +implicitly_return = function(scope) + local is_top = true + local fn + fn = function(stm) + local t = ntype(stm) + if t == "decorated" then + stm = scope.transform.statement(stm) + t = ntype(stm) + end + if types.cascading[t] then + is_top = false + return scope.transform.statement(stm, fn) + elseif types.manual_return[t] or not is_value(stm) then + if is_top and t == "return" and stm[2] == "" then + return NOOP + else + return stm + end + else + if t == "comprehension" and not types.comprehension_has_value(stm) then + return stm + else + return { + "return", + stm + } + end + end + end + return fn +end +local reversed +reversed = require("moonscript.util").reversed +local construct_comprehension +construct_comprehension = function(inner, clauses) + local current_stms = inner + for _, clause in reversed(clauses) do + local t = clause[1] + local _exp_0 = t + if "for" == _exp_0 then + local name, bounds + _, name, bounds = clause[1], clause[2], clause[3] + current_stms = { + "for", + name, + bounds, + current_stms + } + elseif "foreach" == _exp_0 then + local names, iter + _, names, iter = clause[1], clause[2], clause[3] + current_stms = { + "foreach", + names, + { + iter + }, + current_stms + } + elseif "when" == _exp_0 then + local cond + _, cond = clause[1], clause[2] + current_stms = { + "if", + cond, + current_stms + } + else + current_stms = error("Unknown comprehension clause: " .. t) + end + current_stms = { + current_stms + } + end + return current_stms[1] +end return { Run = Run, last_stm = last_stm, transform_last_stm = transform_last_stm, - chain_is_stub = chain_is_stub + chain_is_stub = chain_is_stub, + implicitly_return = implicitly_return, + construct_comprehension = construct_comprehension } diff --git a/moonscript/transform/statements.moon b/moonscript/transform/statements.moon index 59d8e364..3edb0dec 100644 --- a/moonscript/transform/statements.moon +++ b/moonscript/transform/statements.moon @@ -1,5 +1,6 @@ -import ntype, mtype from require "moonscript.types" +types = require "moonscript.types" +import ntype, mtype, is_value, NOOP from types -- A Run is a special statement node that lets a function run and mutate the -- state of the compiler @@ -44,5 +45,56 @@ chain_is_stub = (chain) -> stub = chain[#chain] stub and ntype(stub) == "colon" -{:Run, :last_stm, :transform_last_stm, :chain_is_stub} +implicitly_return = (scope) -> + is_top = true + fn = (stm) -> + t = ntype stm + + -- expand decorated + if t == "decorated" + stm = scope.transform.statement stm + t = ntype stm + + if types.cascading[t] + is_top = false + scope.transform.statement stm, fn + elseif types.manual_return[t] or not is_value stm + -- remove blank return statement + if is_top and t == "return" and stm[2] == "" + NOOP + else + stm + else + if t == "comprehension" and not types.comprehension_has_value stm + stm + else + {"return", stm} + + fn + +-- TODO: reversed unecessary +import reversed from require "moonscript.util" +construct_comprehension = (inner, clauses) -> + current_stms = inner + for _, clause in reversed clauses + t = clause[1] + 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] + +{:Run, :last_stm, :transform_last_stm, :chain_is_stub, :implicitly_return, + :construct_comprehension} diff --git a/moonscript/transform/transformer.lua b/moonscript/transform/transformer.lua new file mode 100644 index 00000000..4ea16959 --- /dev/null +++ b/moonscript/transform/transformer.lua @@ -0,0 +1,74 @@ +local ntype +ntype = require("moonscript.types").ntype +local Transformer +do + local _class_0 + local _base_0 = { + transform_once = function(self, scope, node, ...) + if self.seen_nodes[node] then + return node + end + self.seen_nodes[node] = true + local transformer = self.transformers[ntype(node)] + if transformer then + return transformer(scope, node, ...) or node + else + return node + end + end, + transform = function(self, scope, node, ...) + if self.seen_nodes[node] then + return node + end + self.seen_nodes[node] = true + while true do + local transformer = self.transformers[ntype(node)] + local res + if transformer then + res = transformer(scope, node, ...) or node + else + res = node + end + if res == node then + return node + end + node = res + end + return node + end, + bind = function(self, scope) + return function(...) + return self:transform(scope, ...) + end + end, + __call = function(self, ...) + return self:transform(...) + end, + can_transform = function(self, node) + return self.transformers[ntype(node)] ~= nil + end + } + _base_0.__index = _base_0 + _class_0 = setmetatable({ + __init = function(self, transformers) + self.transformers = transformers + self.seen_nodes = setmetatable({ }, { + __mode = "k" + }) + end, + __base = _base_0, + __name = "Transformer" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + Transformer = _class_0 +end +return { + Transformer = Transformer +} diff --git a/moonscript/transform/transformer.moon b/moonscript/transform/transformer.moon new file mode 100644 index 00000000..8a40c3c7 --- /dev/null +++ b/moonscript/transform/transformer.moon @@ -0,0 +1,42 @@ +import ntype from require "moonscript.types" + +class Transformer + new: (@transformers) => + @seen_nodes = setmetatable {}, __mode: "k" + + transform_once: (scope, node, ...) => + return node if @seen_nodes[node] + @seen_nodes[node] = true + + transformer = @transformers[ntype node] + if transformer + transformer(scope, node, ...) or node + else + node + + transform: (scope, node, ...) => + return node if @seen_nodes[node] + + @seen_nodes[node] = true + while true + transformer = @transformers[ntype node] + res = if transformer + transformer(scope, node, ...) or node + else + node + + return node if res == node + node = res + + node + + bind: (scope) => + (...) -> @transform scope, ... + + __call: (...) => @transform ... + + can_transform: (node) => + @transformers[ntype node] != nil + + +{ :Transformer } diff --git a/moonscript/transform/value.lua b/moonscript/transform/value.lua new file mode 100644 index 00000000..6b56a98e --- /dev/null +++ b/moonscript/transform/value.lua @@ -0,0 +1,261 @@ +local Transformer +Transformer = require("moonscript.transform.transformer").Transformer +local build, ntype, smart_node +do + local _obj_0 = require("moonscript.types") + build, ntype, smart_node = _obj_0.build, _obj_0.ntype, _obj_0.smart_node +end +local NameProxy +NameProxy = require("moonscript.transform.names").NameProxy +local Accumulator, default_accumulator +do + local _obj_0 = require("moonscript.transform.accumulator") + Accumulator, default_accumulator = _obj_0.Accumulator, _obj_0.default_accumulator +end +local lua_keywords +lua_keywords = require("moonscript.data").lua_keywords +local Run, transform_last_stm, implicitly_return, chain_is_stub, construct_comprehension +do + local _obj_0 = require("moonscript.transform.statements") + Run, transform_last_stm, implicitly_return, chain_is_stub, construct_comprehension = _obj_0.Run, _obj_0.transform_last_stm, _obj_0.implicitly_return, _obj_0.chain_is_stub, _obj_0.construct_comprehension +end +local insert +insert = table.insert +return Transformer({ + ["for"] = default_accumulator, + ["while"] = default_accumulator, + foreach = default_accumulator, + ["do"] = function(self, node) + return build.block_exp(node[2]) + end, + decorated = function(self, node) + return self.transform.statement(node) + end, + class = function(self, node) + return build.block_exp({ + node + }) + end, + string = function(self, node) + local delim = node[2] + local convert_part + convert_part = function(part) + if type(part) == "string" or part == nil then + return { + "string", + delim, + part or "" + } + else + return build.chain({ + base = "tostring", + { + "call", + { + part[2] + } + } + }) + end + end + if #node <= 3 then + if type(node[3]) == "string" then + return node + else + return convert_part(node[3]) + end + end + local e = { + "exp", + convert_part(node[3]) + } + for i = 4, #node do + insert(e, "..") + insert(e, convert_part(node[i])) + end + return e + end, + comprehension = function(self, node) + local a = Accumulator() + node = self.transform.statement(node, function(exp) + return a:mutate_body({ + exp + }) + end) + return a:wrap(node) + end, + tblcomprehension = function(self, node) + local _, explist, clauses = unpack(node) + local key_exp, value_exp = unpack(explist) + local accum = NameProxy("tbl") + local inner + if value_exp then + local dest = build.chain({ + base = accum, + { + "index", + key_exp + } + }) + inner = { + build.assign_one(dest, value_exp) + } + else + local key_name, val_name = NameProxy("key"), NameProxy("val") + local dest = build.chain({ + base = accum, + { + "index", + key_name + } + }) + inner = { + build.assign({ + names = { + key_name, + val_name + }, + values = { + key_exp + } + }), + build.assign_one(dest, val_name) + } + end + return build.block_exp({ + build.assign_one(accum, build.table()), + construct_comprehension(inner, clauses), + accum + }) + end, + fndef = function(self, node) + smart_node(node) + node.body = transform_last_stm(node.body, implicitly_return(self)) + node.body = { + Run(function(self) + return self:listen("varargs", function() end) + end), + unpack(node.body) + } + return node + end, + ["if"] = function(self, node) + return build.block_exp({ + node + }) + end, + unless = function(self, node) + return build.block_exp({ + node + }) + end, + with = function(self, node) + return build.block_exp({ + node + }) + end, + switch = function(self, node) + return build.block_exp({ + node + }) + end, + chain = function(self, node) + for i = 2, #node do + local part = node[i] + if ntype(part) == "dot" and lua_keywords[part[2]] then + node[i] = { + "index", + { + "string", + '"', + part[2] + } + } + end + end + if ntype(node[2]) == "string" then + node[2] = { + "parens", + node[2] + } + end + if chain_is_stub(node) then + local base_name = NameProxy("base") + local fn_name = NameProxy("fn") + local colon = table.remove(node) + local is_super = ntype(node[2]) == "ref" and node[2][2] == "super" + return build.block_exp({ + build.assign({ + names = { + base_name + }, + values = { + node + } + }), + build.assign({ + names = { + fn_name + }, + values = { + build.chain({ + base = base_name, + { + "dot", + colon[2] + } + }) + } + }), + build.fndef({ + args = { + { + "..." + } + }, + body = { + build.chain({ + base = fn_name, + { + "call", + { + is_super and "self" or base_name, + "..." + } + } + }) + } + }) + }) + end + end, + block_exp = function(self, node) + local _, body = unpack(node) + local fn = nil + local arg_list = { } + fn = smart_node(build.fndef({ + body = { + Run(function(self) + return self:listen("varargs", function() + insert(arg_list, "...") + insert(fn.args, { + "..." + }) + return self:unlisten("varargs") + end) + end), + unpack(body) + } + })) + return build.chain({ + base = { + "parens", + fn + }, + { + "call", + arg_list + } + }) + end +}) diff --git a/moonscript/transform/value.moon b/moonscript/transform/value.moon new file mode 100644 index 00000000..2b3491e6 --- /dev/null +++ b/moonscript/transform/value.moon @@ -0,0 +1,162 @@ +import Transformer from require "moonscript.transform.transformer" +import build, ntype, smart_node from require "moonscript.types" + +import NameProxy from require "moonscript.transform.names" +import Accumulator, default_accumulator from require "moonscript.transform.accumulator" +import lua_keywords from require "moonscript.data" + +import Run, transform_last_stm, implicitly_return, chain_is_stub, + construct_comprehension from require "moonscript.transform.statements" + +import insert from table + +Transformer { + for: default_accumulator + while: default_accumulator + foreach: default_accumulator + + do: (node) => + build.block_exp node[2] + + decorated: (node) => + @transform.statement node + + class: (node) => + build.block_exp { node } + + string: (node) => + delim = node[2] + + convert_part = (part) -> + if type(part) == "string" or part == nil + {"string", delim, part or ""} + else + build.chain { base: "tostring", {"call", {part[2]}} } + + -- reduced to single item + if #node <= 3 + return if type(node[3]) == "string" + node + else + convert_part node[3] + + e = {"exp", convert_part node[3]} + + for i=4, #node + insert e, ".." + insert e, convert_part node[i] + e + + comprehension: (node) => + a = Accumulator! + node = @transform.statement node, (exp) -> + a\mutate_body {exp} + a\wrap node + + tblcomprehension: (node) => + _, explist, clauses = unpack node + key_exp, value_exp = unpack explist + + accum = NameProxy "tbl" + + inner = if value_exp + dest = build.chain { base: accum, {"index", key_exp} } + { build.assign_one dest, value_exp } + else + -- If we only have single expression then + -- unpack the result into key and value + key_name, val_name = NameProxy"key", NameProxy"val" + dest = build.chain { base: accum, {"index", key_name} } + { + build.assign names: {key_name, val_name}, values: {key_exp} + build.assign_one dest, val_name + } + + build.block_exp { + build.assign_one accum, build.table! + construct_comprehension inner, clauses + accum + } + + fndef: (node) => + smart_node node + node.body = transform_last_stm node.body, implicitly_return self + node.body = { + Run => @listen "varargs", -> -- capture event + unpack node.body + } + + node + + if: (node) => + build.block_exp { node } + + unless: (node) => + build.block_exp { node } + + with: (node) => + build.block_exp { node } + + switch: (node) => + build.block_exp { node } + + -- pull out colon chain + chain: (node) => + -- escape lua keywords used in dot accessors + for i=2,#node + part = node[i] + if ntype(part) == "dot" and lua_keywords[part[2]] + node[i] = { "index", {"string", '"', part[2]} } + + if ntype(node[2]) == "string" + -- add parens if callee is raw string + node[2] = {"parens", node[2] } + + if chain_is_stub node + base_name = NameProxy "base" + fn_name = NameProxy "fn" + colon = table.remove node + + is_super = ntype(node[2]) == "ref" and node[2][2] == "super" + build.block_exp { + build.assign { + names: {base_name} + values: {node} + } + + build.assign { + names: {fn_name} + values: { + build.chain { base: base_name, {"dot", colon[2]} } + } + } + + build.fndef { + args: {{"..."}} + body: { + build.chain { + base: fn_name, {"call", {is_super and "self" or base_name, "..."}} + } + } + } + } + + block_exp: (node) => + _, body = unpack node + + fn = nil + arg_list = {} + + fn = smart_node build.fndef body: { + Run => + @listen "varargs", -> + insert arg_list, "..." + insert fn.args, {"..."} + @unlisten "varargs" + + unpack body + } + + build.chain { base: {"parens", fn}, {"call", arg_list} } +} + diff --git a/moonscript/types.lua b/moonscript/types.lua index a8bd6c70..64ea3651 100644 --- a/moonscript/types.lua +++ b/moonscript/types.lua @@ -308,6 +308,9 @@ local smart_node smart_node = function(node) return setmetatable(node, smart_node_mt[ntype(node)]) end +local NOOP = { + "noop" +} return { ntype = ntype, smart_node = smart_node, @@ -320,5 +323,6 @@ return { comprehension_has_value = comprehension_has_value, value_can_be_statement = value_can_be_statement, mtype = mtype, - terminating = terminating + terminating = terminating, + NOOP = NOOP } diff --git a/moonscript/types.moon b/moonscript/types.moon index abac3110..a2360330 100644 --- a/moonscript/types.moon +++ b/moonscript/types.moon @@ -189,9 +189,12 @@ smart_node_mt = setmetatable {}, { smart_node = (node) -> setmetatable node, smart_node_mt[ntype node] +NOOP = {"noop"} + { :ntype, :smart_node, :build, :is_value, :is_slice, :manual_return, :cascading, :value_is_singular, :comprehension_has_value, :value_can_be_statement, :mtype, :terminating + :NOOP } From 292337ee2bdc1a1b75a03e4648899b69a8c5fc9b Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 5 Dec 2015 23:09:17 -0800 Subject: [PATCH 322/554] update rockpsec (unbreak lint) --- moonscript-dev-1.rockspec | 4 ++++ moonscript/cmd/lint.lua | 3 --- moonscript/cmd/lint.moon | 1 - 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/moonscript-dev-1.rockspec b/moonscript-dev-1.rockspec index 68c82d52..94631056 100644 --- a/moonscript-dev-1.rockspec +++ b/moonscript-dev-1.rockspec @@ -42,9 +42,13 @@ build = { ["moonscript.parse.literals"] = "moonscript/parse/literals.lua", ["moonscript.parse.util"] = "moonscript/parse/util.lua", ["moonscript.transform"] = "moonscript/transform.lua", + ["moonscript.transform.accumulator"] = "moonscript/transform/accumulator.lua", ["moonscript.transform.destructure"] = "moonscript/transform/destructure.lua", ["moonscript.transform.names"] = "moonscript/transform/names.lua", + ["moonscript.transform.statement"] = "moonscript/transform/statement.lua", ["moonscript.transform.statements"] = "moonscript/transform/statements.lua", + ["moonscript.transform.transformer"] = "moonscript/transform/transformer.lua", + ["moonscript.transform.value"] = "moonscript/transform/value.lua", ["moonscript.types"] = "moonscript/types.lua", ["moonscript.util"] = "moonscript/util.lua", ["moonscript.version"] = "moonscript/version.lua", diff --git a/moonscript/cmd/lint.lua b/moonscript/cmd/lint.lua index 55f018b5..50509e57 100644 --- a/moonscript/cmd/lint.lua +++ b/moonscript/cmd/lint.lua @@ -65,9 +65,6 @@ do end end, lint_check_unused = function(self) - do - return - end if not (self.lint_unused_names and next(self.lint_unused_names)) then return end diff --git a/moonscript/cmd/lint.moon b/moonscript/cmd/lint.moon index 853bab59..103c25ed 100644 --- a/moonscript/cmd/lint.moon +++ b/moonscript/cmd/lint.moon @@ -105,7 +105,6 @@ class LinterBlock extends Block @parent\lint_mark_used name lint_check_unused: => - do return return unless @lint_unused_names and next @lint_unused_names names_by_position = {} From 5a0c5d1e5577ab4feb00ea5f8dea1e091b0f755e Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 6 Dec 2015 00:02:55 -0800 Subject: [PATCH 323/554] move comprehension to new module --- moonscript-dev-1.rockspec | 1 + moonscript/transform/comprehension.lua | 55 +++++++++++++++++++++++++ moonscript/transform/comprehension.moon | 30 ++++++++++++++ moonscript/transform/statement.lua | 6 ++- moonscript/transform/statement.moon | 5 ++- moonscript/transform/statements.lua | 52 ++--------------------- moonscript/transform/statements.moon | 30 ++------------ moonscript/transform/value.lua | 6 ++- moonscript/transform/value.moon | 5 ++- moonscript/types.lua | 5 --- moonscript/types.moon | 5 +-- 11 files changed, 109 insertions(+), 91 deletions(-) create mode 100644 moonscript/transform/comprehension.lua create mode 100644 moonscript/transform/comprehension.moon diff --git a/moonscript-dev-1.rockspec b/moonscript-dev-1.rockspec index 94631056..734ac3e1 100644 --- a/moonscript-dev-1.rockspec +++ b/moonscript-dev-1.rockspec @@ -43,6 +43,7 @@ build = { ["moonscript.parse.util"] = "moonscript/parse/util.lua", ["moonscript.transform"] = "moonscript/transform.lua", ["moonscript.transform.accumulator"] = "moonscript/transform/accumulator.lua", + ["moonscript.transform.comprehension"] = "moonscript/transform/comprehension.lua", ["moonscript.transform.destructure"] = "moonscript/transform/destructure.lua", ["moonscript.transform.names"] = "moonscript/transform/names.lua", ["moonscript.transform.statement"] = "moonscript/transform/statement.lua", diff --git a/moonscript/transform/comprehension.lua b/moonscript/transform/comprehension.lua new file mode 100644 index 00000000..1c1fb5f8 --- /dev/null +++ b/moonscript/transform/comprehension.lua @@ -0,0 +1,55 @@ +local is_value +is_value = require("moonscript.types").is_value +local reversed +reversed = require("moonscript.util").reversed +local construct_comprehension +construct_comprehension = function(inner, clauses) + local current_stms = inner + for _, clause in reversed(clauses) do + local t = clause[1] + local _exp_0 = t + if "for" == _exp_0 then + local name, bounds + _, name, bounds = clause[1], clause[2], clause[3] + current_stms = { + "for", + name, + bounds, + current_stms + } + elseif "foreach" == _exp_0 then + local names, iter + _, names, iter = clause[1], clause[2], clause[3] + current_stms = { + "foreach", + names, + { + iter + }, + current_stms + } + elseif "when" == _exp_0 then + local cond + _, cond = clause[1], clause[2] + current_stms = { + "if", + cond, + current_stms + } + else + current_stms = error("Unknown comprehension clause: " .. t) + end + current_stms = { + current_stms + } + end + return current_stms[1] +end +local comprehension_has_value +comprehension_has_value = function(comp) + return is_value(comp[2]) +end +return { + construct_comprehension = construct_comprehension, + comprehension_has_value = comprehension_has_value +} diff --git a/moonscript/transform/comprehension.moon b/moonscript/transform/comprehension.moon new file mode 100644 index 00000000..61f9696f --- /dev/null +++ b/moonscript/transform/comprehension.moon @@ -0,0 +1,30 @@ + +import is_value from require "moonscript.types" + +-- TODO: reversed unecessary +import reversed from require "moonscript.util" +construct_comprehension = (inner, clauses) -> + current_stms = inner + for _, clause in reversed clauses + t = clause[1] + 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] + +comprehension_has_value = (comp) -> + is_value comp[2] + +{:construct_comprehension, :comprehension_has_value} diff --git a/moonscript/transform/statement.lua b/moonscript/transform/statement.lua index 683fb90c..77d0d3ec 100644 --- a/moonscript/transform/statement.lua +++ b/moonscript/transform/statement.lua @@ -5,10 +5,10 @@ do local _obj_0 = require("moonscript.transform.names") NameProxy, LocalName = _obj_0.NameProxy, _obj_0.LocalName end -local Run, transform_last_stm, implicitly_return, construct_comprehension, last_stm +local Run, transform_last_stm, implicitly_return, last_stm do local _obj_0 = require("moonscript.transform.statements") - Run, transform_last_stm, implicitly_return, construct_comprehension, last_stm = _obj_0.Run, _obj_0.transform_last_stm, _obj_0.implicitly_return, _obj_0.construct_comprehension, _obj_0.last_stm + Run, transform_last_stm, implicitly_return, last_stm = _obj_0.Run, _obj_0.transform_last_stm, _obj_0.implicitly_return, _obj_0.last_stm end local types = require("moonscript.types") local build, ntype, is_value, smart_node, value_is_singular, is_slice, NOOP @@ -16,6 +16,8 @@ build, ntype, is_value, smart_node, value_is_singular, is_slice, NOOP = types.bu local insert insert = table.insert local destructure = require("moonscript.transform.destructure") +local construct_comprehension +construct_comprehension = require("moonscript.transform.comprehension").construct_comprehension local CONSTRUCTOR_NAME = "new" local with_continue_listener with_continue_listener = function(body) diff --git a/moonscript/transform/statement.moon b/moonscript/transform/statement.moon index 646403f9..6f4e1691 100644 --- a/moonscript/transform/statement.moon +++ b/moonscript/transform/statement.moon @@ -2,8 +2,8 @@ import Transformer from require "moonscript.transform.transformer" import NameProxy, LocalName from require "moonscript.transform.names" -import Run, transform_last_stm, implicitly_return, construct_comprehension, - last_stm from require "moonscript.transform.statements" +import Run, transform_last_stm, implicitly_return, last_stm + from require "moonscript.transform.statements" types = require "moonscript.types" @@ -13,6 +13,7 @@ import build, ntype, is_value, smart_node, value_is_singular, is_slice, NOOP import insert from table destructure = require "moonscript.transform.destructure" +import construct_comprehension from require "moonscript.transform.comprehension" CONSTRUCTOR_NAME = "new" diff --git a/moonscript/transform/statements.lua b/moonscript/transform/statements.lua index dc562a5d..6a49b77e 100644 --- a/moonscript/transform/statements.lua +++ b/moonscript/transform/statements.lua @@ -1,6 +1,8 @@ local types = require("moonscript.types") local ntype, mtype, is_value, NOOP ntype, mtype, is_value, NOOP = types.ntype, types.mtype, types.is_value, types.NOOP +local comprehension_has_value +comprehension_has_value = require("moonscript.transform.comprehension").comprehension_has_value local Run do local _class_0 @@ -92,7 +94,7 @@ implicitly_return = function(scope) return stm end else - if t == "comprehension" and not types.comprehension_has_value(stm) then + if t == "comprehension" and not comprehension_has_value(stm) then return stm else return { @@ -104,56 +106,10 @@ implicitly_return = function(scope) end return fn end -local reversed -reversed = require("moonscript.util").reversed -local construct_comprehension -construct_comprehension = function(inner, clauses) - local current_stms = inner - for _, clause in reversed(clauses) do - local t = clause[1] - local _exp_0 = t - if "for" == _exp_0 then - local name, bounds - _, name, bounds = clause[1], clause[2], clause[3] - current_stms = { - "for", - name, - bounds, - current_stms - } - elseif "foreach" == _exp_0 then - local names, iter - _, names, iter = clause[1], clause[2], clause[3] - current_stms = { - "foreach", - names, - { - iter - }, - current_stms - } - elseif "when" == _exp_0 then - local cond - _, cond = clause[1], clause[2] - current_stms = { - "if", - cond, - current_stms - } - else - current_stms = error("Unknown comprehension clause: " .. t) - end - current_stms = { - current_stms - } - end - return current_stms[1] -end return { Run = Run, last_stm = last_stm, transform_last_stm = transform_last_stm, chain_is_stub = chain_is_stub, - implicitly_return = implicitly_return, - construct_comprehension = construct_comprehension + implicitly_return = implicitly_return } diff --git a/moonscript/transform/statements.moon b/moonscript/transform/statements.moon index 3edb0dec..164e6b58 100644 --- a/moonscript/transform/statements.moon +++ b/moonscript/transform/statements.moon @@ -2,6 +2,8 @@ types = require "moonscript.types" import ntype, mtype, is_value, NOOP from types +import comprehension_has_value from require "moonscript.transform.comprehension" + -- A Run is a special statement node that lets a function run and mutate the -- state of the compiler class Run @@ -65,36 +67,12 @@ implicitly_return = (scope) -> else stm else - if t == "comprehension" and not types.comprehension_has_value stm + if t == "comprehension" and not comprehension_has_value stm stm else {"return", stm} fn --- TODO: reversed unecessary -import reversed from require "moonscript.util" -construct_comprehension = (inner, clauses) -> - current_stms = inner - for _, clause in reversed clauses - t = clause[1] - 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] - -{:Run, :last_stm, :transform_last_stm, :chain_is_stub, :implicitly_return, - :construct_comprehension} +{:Run, :last_stm, :transform_last_stm, :chain_is_stub, :implicitly_return } diff --git a/moonscript/transform/value.lua b/moonscript/transform/value.lua index 6b56a98e..159ae52a 100644 --- a/moonscript/transform/value.lua +++ b/moonscript/transform/value.lua @@ -14,11 +14,13 @@ do end local lua_keywords lua_keywords = require("moonscript.data").lua_keywords -local Run, transform_last_stm, implicitly_return, chain_is_stub, construct_comprehension +local Run, transform_last_stm, implicitly_return, chain_is_stub do local _obj_0 = require("moonscript.transform.statements") - Run, transform_last_stm, implicitly_return, chain_is_stub, construct_comprehension = _obj_0.Run, _obj_0.transform_last_stm, _obj_0.implicitly_return, _obj_0.chain_is_stub, _obj_0.construct_comprehension + Run, transform_last_stm, implicitly_return, chain_is_stub = _obj_0.Run, _obj_0.transform_last_stm, _obj_0.implicitly_return, _obj_0.chain_is_stub end +local construct_comprehension +construct_comprehension = require("moonscript.transform.comprehension").construct_comprehension local insert insert = table.insert return Transformer({ diff --git a/moonscript/transform/value.moon b/moonscript/transform/value.moon index 2b3491e6..7b415d6f 100644 --- a/moonscript/transform/value.moon +++ b/moonscript/transform/value.moon @@ -5,8 +5,9 @@ import NameProxy from require "moonscript.transform.names" import Accumulator, default_accumulator from require "moonscript.transform.accumulator" import lua_keywords from require "moonscript.data" -import Run, transform_last_stm, implicitly_return, chain_is_stub, - construct_comprehension from require "moonscript.transform.statements" +import Run, transform_last_stm, implicitly_return, chain_is_stub from require "moonscript.transform.statements" + +import construct_comprehension from require "moonscript.transform.comprehension" import insert from table diff --git a/moonscript/types.lua b/moonscript/types.lua index 64ea3651..e8efc409 100644 --- a/moonscript/types.lua +++ b/moonscript/types.lua @@ -58,10 +58,6 @@ is_value = function(stm) local transform = require("moonscript.transform") return compile.Block:is_value(stm) or transform.Value:can_transform(stm) end -local comprehension_has_value -comprehension_has_value = function(comp) - return is_value(comp[2]) -end local value_is_singular value_is_singular = function(node) return type(node) ~= "table" or node[1] ~= "exp" or #node == 2 @@ -320,7 +316,6 @@ return { manual_return = manual_return, cascading = cascading, value_is_singular = value_is_singular, - comprehension_has_value = comprehension_has_value, value_can_be_statement = value_can_be_statement, mtype = mtype, terminating = terminating, diff --git a/moonscript/types.moon b/moonscript/types.moon index a2360330..23f4ed91 100644 --- a/moonscript/types.moon +++ b/moonscript/types.moon @@ -52,9 +52,6 @@ is_value = (stm) -> compile.Block\is_value(stm) or transform.Value\can_transform stm -comprehension_has_value = (comp) -> - is_value comp[2] - value_is_singular = (node) -> type(node) != "table" or node[1] != "exp" or #node == 2 @@ -193,7 +190,7 @@ NOOP = {"noop"} { :ntype, :smart_node, :build, :is_value, :is_slice, :manual_return, - :cascading, :value_is_singular, :comprehension_has_value, + :cascading, :value_is_singular, :value_can_be_statement, :mtype, :terminating :NOOP } From ca21c216ea94a3795dbe47019617b9222b526218 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 6 Dec 2015 00:10:36 -0800 Subject: [PATCH 324/554] move class transformer to own module --- moonscript/transform/class.lua | 436 ++++++++++++++++++++++++++++ moonscript/transform/class.moon | 256 ++++++++++++++++ moonscript/transform/statement.lua | 430 +-------------------------- moonscript/transform/statement.moon | 254 +--------------- 4 files changed, 698 insertions(+), 678 deletions(-) create mode 100644 moonscript/transform/class.lua create mode 100644 moonscript/transform/class.moon diff --git a/moonscript/transform/class.lua b/moonscript/transform/class.lua new file mode 100644 index 00000000..a8ad78b8 --- /dev/null +++ b/moonscript/transform/class.lua @@ -0,0 +1,436 @@ +local NameProxy, LocalName +do + local _obj_0 = require("moonscript.transform.names") + NameProxy, LocalName = _obj_0.NameProxy, _obj_0.LocalName +end +local Run +Run = require("moonscript.transform.statements").Run +local CONSTRUCTOR_NAME = "new" +local insert +insert = table.insert +local build, ntype, NOOP +do + local _obj_0 = require("moonscript.types") + build, ntype, NOOP = _obj_0.build, _obj_0.ntype, _obj_0.NOOP +end +return function(self, node, ret, parent_assign) + local _, name, parent_val, body = unpack(node) + if parent_val == "" then + parent_val = nil + end + local statements = { } + local properties = { } + for _index_0 = 1, #body do + local item = body[_index_0] + local _exp_0 = item[1] + if "stm" == _exp_0 then + insert(statements, item[2]) + elseif "props" == _exp_0 then + for _index_1 = 2, #item do + local tuple = item[_index_1] + if ntype(tuple[1]) == "self" then + insert(statements, build.assign_one(unpack(tuple))) + else + insert(properties, tuple) + end + end + end + end + local constructor + do + local _accum_0 = { } + local _len_0 = 1 + for _index_0 = 1, #properties do + local _continue_0 = false + repeat + local tuple = properties[_index_0] + local key = tuple[1] + local _value_0 + if key[1] == "key_literal" and key[2] == CONSTRUCTOR_NAME then + constructor = tuple[2] + _continue_0 = true + break + else + _value_0 = tuple + end + _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 + _continue_0 = true + until true + if not _continue_0 then + break + end + end + properties = _accum_0 + end + local parent_cls_name = NameProxy("parent") + local base_name = NameProxy("base") + local self_name = NameProxy("self") + local cls_name = NameProxy("class") + if not (constructor) then + if parent_val then + constructor = build.fndef({ + args = { + { + "..." + } + }, + arrow = "fat", + body = { + build.chain({ + base = "super", + { + "call", + { + "..." + } + } + }) + } + }) + else + constructor = build.fndef() + end + end + local real_name = name or parent_assign and parent_assign[2][1] + local _exp_0 = ntype(real_name) + if "chain" == _exp_0 then + local last = real_name[#real_name] + local _exp_1 = ntype(last) + if "dot" == _exp_1 then + real_name = { + "string", + '"', + last[2] + } + elseif "index" == _exp_1 then + real_name = last[2] + else + real_name = "nil" + end + elseif "nil" == _exp_0 then + real_name = "nil" + else + local name_t = type(real_name) + local flattened_name + if name_t == "string" then + flattened_name = real_name + elseif name_t == "table" and real_name[1] == "ref" then + flattened_name = real_name[2] + else + flattened_name = error("don't know how to extract name from " .. tostring(name_t)) + end + real_name = { + "string", + '"', + flattened_name + } + end + local cls = build.table({ + { + "__init", + constructor + }, + { + "__base", + base_name + }, + { + "__name", + real_name + }, + parent_val and { + "__parent", + parent_cls_name + } or nil + }) + local class_index + if parent_val then + local class_lookup = build["if"]({ + cond = { + "exp", + { + "ref", + "val" + }, + "==", + "nil" + }, + ["then"] = { + build.assign_one(LocalName("parent"), build.chain({ + base = "rawget", + { + "call", + { + { + "ref", + "cls" + }, + { + "string", + '"', + "__parent" + } + } + } + })), + build["if"]({ + cond = LocalName("parent"), + ["then"] = { + build.chain({ + base = LocalName("parent"), + { + "index", + "name" + } + }) + } + }) + } + }) + insert(class_lookup, { + "else", + { + "val" + } + }) + class_index = build.fndef({ + args = { + { + "cls" + }, + { + "name" + } + }, + body = { + build.assign_one(LocalName("val"), build.chain({ + base = "rawget", + { + "call", + { + base_name, + { + "ref", + "name" + } + } + } + })), + class_lookup + } + }) + else + class_index = base_name + end + local cls_mt = build.table({ + { + "__index", + class_index + }, + { + "__call", + build.fndef({ + args = { + { + "cls" + }, + { + "..." + } + }, + body = { + build.assign_one(self_name, build.chain({ + base = "setmetatable", + { + "call", + { + "{}", + base_name + } + } + })), + build.chain({ + base = "cls.__init", + { + "call", + { + self_name, + "..." + } + } + }), + self_name + } + }) + } + }) + cls = build.chain({ + base = "setmetatable", + { + "call", + { + cls, + cls_mt + } + } + }) + local value = nil + do + local out_body = { + Run(function(self) + if name then + self:put_name(name) + end + return self:set("super", function(block, chain) + local relative_parent = { + "chain", + cls_name, + { + "dot", + "__parent" + } + } + if not (chain) then + return relative_parent + end + local chain_tail = { + unpack(chain, 3) + } + local head = chain_tail[1] + if head == nil then + return relative_parent + end + local new_chain = relative_parent + local _exp_1 = head[1] + if "call" == _exp_1 then + local calling_name = block:get("current_block") + assert(calling_name, "missing calling name") + chain_tail[1] = { + "call", + { + "self", + unpack(head[2]) + } + } + if ntype(calling_name) == "key_literal" then + insert(new_chain, { + "dot", + calling_name[2] + }) + else + insert(new_chain, { + "index", + calling_name + }) + end + elseif "colon" == _exp_1 then + local call = chain_tail[2] + if call and call[1] == "call" then + chain_tail[1] = { + "dot", + head[2] + } + chain_tail[2] = { + "call", + { + "self", + unpack(call[2]) + } + } + end + end + for _index_0 = 1, #chain_tail do + local item = chain_tail[_index_0] + insert(new_chain, item) + end + return new_chain + end) + end), + { + "declare", + { + cls_name + } + }, + { + "declare_glob", + "*" + }, + parent_val and build.assign_one(parent_cls_name, parent_val) or NOOP, + build.assign_one(base_name, { + "table", + properties + }), + build.assign_one(base_name:chain("__index"), base_name), + parent_val and build.chain({ + base = "setmetatable", + { + "call", + { + base_name, + build.chain({ + base = parent_cls_name, + { + "dot", + "__base" + } + }) + } + } + }) or NOOP, + build.assign_one(cls_name, cls), + build.assign_one(base_name:chain("__class"), cls_name), + build.group((function() + if #statements > 0 then + return { + build.assign_one(LocalName("self"), cls_name), + build.group(statements) + } + end + end)()), + parent_val and build["if"]({ + cond = { + "exp", + parent_cls_name:chain("__inherited") + }, + ["then"] = { + parent_cls_name:chain("__inherited", { + "call", + { + parent_cls_name, + cls_name + } + }) + } + }) or NOOP, + build.group((function() + if name then + return { + build.assign_one(name, cls_name) + } + end + end)()), + (function() + if ret then + return ret(cls_name) + end + end)() + } + value = build.group({ + build.group((function() + if ntype(name) == "value" then + return { + build.declare({ + names = { + name + } + }) + } + end + end)()), + build["do"](out_body) + }) + end + return value +end diff --git a/moonscript/transform/class.moon b/moonscript/transform/class.moon new file mode 100644 index 00000000..007baced --- /dev/null +++ b/moonscript/transform/class.moon @@ -0,0 +1,256 @@ +import NameProxy, LocalName from require "moonscript.transform.names" +import Run from require "moonscript.transform.statements" + +CONSTRUCTOR_NAME = "new" + +import insert from table +import build, ntype, NOOP from require "moonscript.types" + +(node, ret, parent_assign) => + _, name, parent_val, body = unpack node + parent_val = nil if parent_val == "" + + -- split apart properties and statements + statements = {} + properties = {} + for item in *body + switch item[1] + when "stm" + insert statements, item[2] + when "props" + for tuple in *item[2,] + if ntype(tuple[1]) == "self" + insert statements, build.assign_one unpack tuple + else + insert properties, tuple + + -- find constructor + local constructor + properties = for tuple in *properties + key = tuple[1] + if key[1] == "key_literal" and key[2] == CONSTRUCTOR_NAME + constructor = tuple[2] + continue + else + tuple + + parent_cls_name = NameProxy "parent" + base_name = NameProxy "base" + self_name = NameProxy "self" + cls_name = NameProxy "class" + + unless constructor + constructor = if parent_val + build.fndef { + args: {{"..."}} + arrow: "fat" + body: { + build.chain { base: "super", {"call", {"..."}} } + } + } + else + build.fndef! + + real_name = name or parent_assign and parent_assign[2][1] + real_name = switch ntype real_name + when "chain" + last = real_name[#real_name] + switch ntype last + when "dot" + {"string", '"', last[2]} + when "index" + last[2] + else + "nil" + when "nil" + "nil" + else + name_t = type real_name + -- TODO: don't use string literal as ref + flattened_name = if name_t == "string" + real_name + elseif name_t == "table" and real_name[1] == "ref" + real_name[2] + else + error "don't know how to extract name from #{name_t}" + + {"string", '"', flattened_name} + + cls = build.table { + {"__init", constructor} + {"__base", base_name} + {"__name", real_name} -- "quote the string" + parent_val and {"__parent", parent_cls_name} or nil + } + + -- looking up a name in the class object + class_index = if parent_val + class_lookup = build["if"] { + cond: { "exp", {"ref", "val"}, "==", "nil" } + then: { + build.assign_one LocalName"parent", build.chain { + base: "rawget" + { + "call", { + {"ref", "cls"} + {"string", '"', "__parent"} + } + } + } + + build.if { + cond: LocalName "parent" + then: { + build.chain { + base: LocalName "parent" + {"index", "name"} + } + } + } + } + } + insert class_lookup, {"else", {"val"}} + + build.fndef { + args: {{"cls"}, {"name"}} + body: { + build.assign_one LocalName"val", build.chain { + base: "rawget", {"call", {base_name, {"ref", "name"}}} + } + class_lookup + } + } + else + base_name + + cls_mt = build.table { + {"__index", class_index} + {"__call", build.fndef { + args: {{"cls"}, {"..."}} + body: { + build.assign_one self_name, build.chain { + base: "setmetatable" + {"call", {"{}", base_name}} + } + build.chain { + base: "cls.__init" + {"call", {self_name, "..."}} + } + self_name + } + }} + } + + cls = build.chain { + base: "setmetatable" + {"call", {cls, cls_mt}} + } + + value = nil + with build + out_body = { + Run => + -- make sure we don't assign the class to a local inside the do + @put_name name if name + + @set "super", (block, chain) -> + relative_parent = { + "chain", + cls_name + {"dot", "__parent"} + } + + return relative_parent unless chain + + chain_tail = { unpack chain, 3 } + head = chain_tail[1] + + if head == nil + return relative_parent + + new_chain = relative_parent + + switch head[1] + -- calling super, inject calling name and self into chain + when "call" + calling_name = block\get"current_block" + assert calling_name, "missing calling name" + chain_tail[1] = {"call", {"self", unpack head[2]}} + + if ntype(calling_name) == "key_literal" + insert new_chain, {"dot", calling_name[2]} + else + insert new_chain, {"index", calling_name} + + -- colon call on super, replace class with self as first arg + when "colon" + call = chain_tail[2] + -- calling chain tail + if call and call[1] == "call" + chain_tail[1] = { + "dot" + head[2] + } + + chain_tail[2] = { + "call" + { + "self" + unpack call[2] + } + } + + insert new_chain, item for item in *chain_tail + new_chain + + {"declare", { cls_name }} + {"declare_glob", "*"} + + parent_val and .assign_one(parent_cls_name, parent_val) or NOOP + + .assign_one base_name, {"table", properties} + .assign_one base_name\chain"__index", base_name + + parent_val and .chain({ + base: "setmetatable" + {"call", { + base_name, + .chain { base: parent_cls_name, {"dot", "__base"}} + }} + }) or NOOP + + .assign_one cls_name, cls + .assign_one base_name\chain"__class", cls_name + + .group if #statements > 0 then { + .assign_one LocalName"self", cls_name + .group statements + } + + -- run the inherited callback + parent_val and .if({ + cond: {"exp", parent_cls_name\chain "__inherited" } + then: { + parent_cls_name\chain "__inherited", {"call", { + parent_cls_name, cls_name + }} + } + }) or NOOP + + .group if name then { + .assign_one name, cls_name + } + + if ret + ret cls_name + } + + value = .group { + .group if ntype(name) == "value" then { + .declare names: {name} + } + + .do out_body + } + + value diff --git a/moonscript/transform/statement.lua b/moonscript/transform/statement.lua index 77d0d3ec..f37a9d6f 100644 --- a/moonscript/transform/statement.lua +++ b/moonscript/transform/statement.lua @@ -1,10 +1,7 @@ local Transformer Transformer = require("moonscript.transform.transformer").Transformer -local NameProxy, LocalName -do - local _obj_0 = require("moonscript.transform.names") - NameProxy, LocalName = _obj_0.NameProxy, _obj_0.LocalName -end +local NameProxy +NameProxy = require("moonscript.transform.names").NameProxy local Run, transform_last_stm, implicitly_return, last_stm do local _obj_0 = require("moonscript.transform.statements") @@ -18,7 +15,6 @@ insert = table.insert local destructure = require("moonscript.transform.destructure") local construct_comprehension construct_comprehension = require("moonscript.transform.comprehension").construct_comprehension -local CONSTRUCTOR_NAME = "new" local with_continue_listener with_continue_listener = function(body) local continue_name = nil @@ -739,425 +735,5 @@ return Transformer({ if_stm }) end, - class = function(self, node, ret, parent_assign) - local _, name, parent_val, body = unpack(node) - if parent_val == "" then - parent_val = nil - end - local statements = { } - local properties = { } - for _index_0 = 1, #body do - local item = body[_index_0] - local _exp_0 = item[1] - if "stm" == _exp_0 then - insert(statements, item[2]) - elseif "props" == _exp_0 then - for _index_1 = 2, #item do - local tuple = item[_index_1] - if ntype(tuple[1]) == "self" then - insert(statements, build.assign_one(unpack(tuple))) - else - insert(properties, tuple) - end - end - end - end - local constructor - do - local _accum_0 = { } - local _len_0 = 1 - for _index_0 = 1, #properties do - local _continue_0 = false - repeat - local tuple = properties[_index_0] - local key = tuple[1] - local _value_0 - if key[1] == "key_literal" and key[2] == CONSTRUCTOR_NAME then - constructor = tuple[2] - _continue_0 = true - break - else - _value_0 = tuple - end - _accum_0[_len_0] = _value_0 - _len_0 = _len_0 + 1 - _continue_0 = true - until true - if not _continue_0 then - break - end - end - properties = _accum_0 - end - local parent_cls_name = NameProxy("parent") - local base_name = NameProxy("base") - local self_name = NameProxy("self") - local cls_name = NameProxy("class") - if not (constructor) then - if parent_val then - constructor = build.fndef({ - args = { - { - "..." - } - }, - arrow = "fat", - body = { - build.chain({ - base = "super", - { - "call", - { - "..." - } - } - }) - } - }) - else - constructor = build.fndef() - end - end - local real_name = name or parent_assign and parent_assign[2][1] - local _exp_0 = ntype(real_name) - if "chain" == _exp_0 then - local last = real_name[#real_name] - local _exp_1 = ntype(last) - if "dot" == _exp_1 then - real_name = { - "string", - '"', - last[2] - } - elseif "index" == _exp_1 then - real_name = last[2] - else - real_name = "nil" - end - elseif "nil" == _exp_0 then - real_name = "nil" - else - local name_t = type(real_name) - local flattened_name - if name_t == "string" then - flattened_name = real_name - elseif name_t == "table" and real_name[1] == "ref" then - flattened_name = real_name[2] - else - flattened_name = error("don't know how to extract name from " .. tostring(name_t)) - end - real_name = { - "string", - '"', - flattened_name - } - end - local cls = build.table({ - { - "__init", - constructor - }, - { - "__base", - base_name - }, - { - "__name", - real_name - }, - parent_val and { - "__parent", - parent_cls_name - } or nil - }) - local class_index - if parent_val then - local class_lookup = build["if"]({ - cond = { - "exp", - { - "ref", - "val" - }, - "==", - "nil" - }, - ["then"] = { - build.assign_one(LocalName("parent"), build.chain({ - base = "rawget", - { - "call", - { - { - "ref", - "cls" - }, - { - "string", - '"', - "__parent" - } - } - } - })), - build["if"]({ - cond = LocalName("parent"), - ["then"] = { - build.chain({ - base = LocalName("parent"), - { - "index", - "name" - } - }) - } - }) - } - }) - insert(class_lookup, { - "else", - { - "val" - } - }) - class_index = build.fndef({ - args = { - { - "cls" - }, - { - "name" - } - }, - body = { - build.assign_one(LocalName("val"), build.chain({ - base = "rawget", - { - "call", - { - base_name, - { - "ref", - "name" - } - } - } - })), - class_lookup - } - }) - else - class_index = base_name - end - local cls_mt = build.table({ - { - "__index", - class_index - }, - { - "__call", - build.fndef({ - args = { - { - "cls" - }, - { - "..." - } - }, - body = { - build.assign_one(self_name, build.chain({ - base = "setmetatable", - { - "call", - { - "{}", - base_name - } - } - })), - build.chain({ - base = "cls.__init", - { - "call", - { - self_name, - "..." - } - } - }), - self_name - } - }) - } - }) - cls = build.chain({ - base = "setmetatable", - { - "call", - { - cls, - cls_mt - } - } - }) - local value = nil - do - local out_body = { - Run(function(self) - if name then - self:put_name(name) - end - return self:set("super", function(block, chain) - local relative_parent = { - "chain", - cls_name, - { - "dot", - "__parent" - } - } - if not (chain) then - return relative_parent - end - local chain_tail = { - unpack(chain, 3) - } - local head = chain_tail[1] - if head == nil then - return relative_parent - end - local new_chain = relative_parent - local _exp_1 = head[1] - if "call" == _exp_1 then - local calling_name = block:get("current_block") - assert(calling_name, "missing calling name") - chain_tail[1] = { - "call", - { - "self", - unpack(head[2]) - } - } - if ntype(calling_name) == "key_literal" then - insert(new_chain, { - "dot", - calling_name[2] - }) - else - insert(new_chain, { - "index", - calling_name - }) - end - elseif "colon" == _exp_1 then - local call = chain_tail[2] - if call and call[1] == "call" then - chain_tail[1] = { - "dot", - head[2] - } - chain_tail[2] = { - "call", - { - "self", - unpack(call[2]) - } - } - end - end - for _index_0 = 1, #chain_tail do - local item = chain_tail[_index_0] - insert(new_chain, item) - end - return new_chain - end) - end), - { - "declare", - { - cls_name - } - }, - { - "declare_glob", - "*" - }, - parent_val and build.assign_one(parent_cls_name, parent_val) or NOOP, - build.assign_one(base_name, { - "table", - properties - }), - build.assign_one(base_name:chain("__index"), base_name), - parent_val and build.chain({ - base = "setmetatable", - { - "call", - { - base_name, - build.chain({ - base = parent_cls_name, - { - "dot", - "__base" - } - }) - } - } - }) or NOOP, - build.assign_one(cls_name, cls), - build.assign_one(base_name:chain("__class"), cls_name), - build.group((function() - if #statements > 0 then - return { - build.assign_one(LocalName("self"), cls_name), - build.group(statements) - } - end - end)()), - parent_val and build["if"]({ - cond = { - "exp", - parent_cls_name:chain("__inherited") - }, - ["then"] = { - parent_cls_name:chain("__inherited", { - "call", - { - parent_cls_name, - cls_name - } - }) - } - }) or NOOP, - build.group((function() - if name then - return { - build.assign_one(name, cls_name) - } - end - end)()), - (function() - if ret then - return ret(cls_name) - end - end)() - } - value = build.group({ - build.group((function() - if ntype(name) == "value" then - return { - build.declare({ - names = { - name - } - }) - } - end - end)()), - build["do"](out_body) - }) - end - return value - end + class = require("moonscript.transform.class") }) diff --git a/moonscript/transform/statement.moon b/moonscript/transform/statement.moon index 6f4e1691..7933c5fe 100644 --- a/moonscript/transform/statement.moon +++ b/moonscript/transform/statement.moon @@ -1,6 +1,6 @@ import Transformer from require "moonscript.transform.transformer" -import NameProxy, LocalName from require "moonscript.transform.names" +import NameProxy from require "moonscript.transform.names" import Run, transform_last_stm, implicitly_return, last_stm from require "moonscript.transform.statements" @@ -15,8 +15,6 @@ import insert from table destructure = require "moonscript.transform.destructure" import construct_comprehension from require "moonscript.transform.comprehension" -CONSTRUCTOR_NAME = "new" - with_continue_listener = (body) -> continue_name = nil @@ -470,252 +468,6 @@ Transformer { if_stm } - class: (node, ret, parent_assign) => - _, name, parent_val, body = unpack node - parent_val = nil if parent_val == "" - - -- split apart properties and statements - statements = {} - properties = {} - for item in *body - switch item[1] - when "stm" - insert statements, item[2] - when "props" - for tuple in *item[2,] - if ntype(tuple[1]) == "self" - insert statements, build.assign_one unpack tuple - else - insert properties, tuple - - -- find constructor - local constructor - properties = for tuple in *properties - key = tuple[1] - if key[1] == "key_literal" and key[2] == CONSTRUCTOR_NAME - constructor = tuple[2] - continue - else - tuple - - parent_cls_name = NameProxy "parent" - base_name = NameProxy "base" - self_name = NameProxy "self" - cls_name = NameProxy "class" - - unless constructor - constructor = if parent_val - build.fndef { - args: {{"..."}} - arrow: "fat" - body: { - build.chain { base: "super", {"call", {"..."}} } - } - } - else - build.fndef! - - real_name = name or parent_assign and parent_assign[2][1] - real_name = switch ntype real_name - when "chain" - last = real_name[#real_name] - switch ntype last - when "dot" - {"string", '"', last[2]} - when "index" - last[2] - else - "nil" - when "nil" - "nil" - else - name_t = type real_name - -- TODO: don't use string literal as ref - flattened_name = if name_t == "string" - real_name - elseif name_t == "table" and real_name[1] == "ref" - real_name[2] - else - error "don't know how to extract name from #{name_t}" - - {"string", '"', flattened_name} - - cls = build.table { - {"__init", constructor} - {"__base", base_name} - {"__name", real_name} -- "quote the string" - parent_val and {"__parent", parent_cls_name} or nil - } - - -- looking up a name in the class object - class_index = if parent_val - class_lookup = build["if"] { - cond: { "exp", {"ref", "val"}, "==", "nil" } - then: { - build.assign_one LocalName"parent", build.chain { - base: "rawget" - { - "call", { - {"ref", "cls"} - {"string", '"', "__parent"} - } - } - } - - build.if { - cond: LocalName "parent" - then: { - build.chain { - base: LocalName "parent" - {"index", "name"} - } - } - } - } - } - insert class_lookup, {"else", {"val"}} - - build.fndef { - args: {{"cls"}, {"name"}} - body: { - build.assign_one LocalName"val", build.chain { - base: "rawget", {"call", {base_name, {"ref", "name"}}} - } - class_lookup - } - } - else - base_name - - cls_mt = build.table { - {"__index", class_index} - {"__call", build.fndef { - args: {{"cls"}, {"..."}} - body: { - build.assign_one self_name, build.chain { - base: "setmetatable" - {"call", {"{}", base_name}} - } - build.chain { - base: "cls.__init" - {"call", {self_name, "..."}} - } - self_name - } - }} - } - - cls = build.chain { - base: "setmetatable" - {"call", {cls, cls_mt}} - } - - value = nil - with build - out_body = { - Run => - -- make sure we don't assign the class to a local inside the do - @put_name name if name - - @set "super", (block, chain) -> - relative_parent = { - "chain", - cls_name - {"dot", "__parent"} - } - - return relative_parent unless chain - - chain_tail = { unpack chain, 3 } - head = chain_tail[1] - - if head == nil - return relative_parent - - new_chain = relative_parent - - switch head[1] - -- calling super, inject calling name and self into chain - when "call" - calling_name = block\get"current_block" - assert calling_name, "missing calling name" - chain_tail[1] = {"call", {"self", unpack head[2]}} - - if ntype(calling_name) == "key_literal" - insert new_chain, {"dot", calling_name[2]} - else - insert new_chain, {"index", calling_name} - - -- colon call on super, replace class with self as first arg - when "colon" - call = chain_tail[2] - -- calling chain tail - if call and call[1] == "call" - chain_tail[1] = { - "dot" - head[2] - } - - chain_tail[2] = { - "call" - { - "self" - unpack call[2] - } - } - - insert new_chain, item for item in *chain_tail - new_chain - - {"declare", { cls_name }} - {"declare_glob", "*"} - - parent_val and .assign_one(parent_cls_name, parent_val) or NOOP - - .assign_one base_name, {"table", properties} - .assign_one base_name\chain"__index", base_name - - parent_val and .chain({ - base: "setmetatable" - {"call", { - base_name, - .chain { base: parent_cls_name, {"dot", "__base"}} - }} - }) or NOOP - - .assign_one cls_name, cls - .assign_one base_name\chain"__class", cls_name - - .group if #statements > 0 then { - .assign_one LocalName"self", cls_name - .group statements - } - - -- run the inherited callback - parent_val and .if({ - cond: {"exp", parent_cls_name\chain "__inherited" } - then: { - parent_cls_name\chain "__inherited", {"call", { - parent_cls_name, cls_name - }} - } - }) or NOOP - - .group if name then { - .assign_one name, cls_name - } - - if ret - ret cls_name - } - - value = .group { - .group if ntype(name) == "value" then { - .declare names: {name} - } - - .do out_body - } - - value + class: require "moonscript.transform.class" + } From 07c639ad3db985a67c3bf62c04eb39386f8be65a Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 6 Dec 2015 00:14:47 -0800 Subject: [PATCH 325/554] remove reversed --- moonscript/compile/statement.lua | 3 --- moonscript/compile/statement.moon | 3 --- moonscript/transform/comprehension.lua | 11 +++++------ moonscript/transform/comprehension.moon | 6 +++--- moonscript/util.lua | 9 --------- moonscript/util.moon | 9 ++------- 6 files changed, 10 insertions(+), 31 deletions(-) diff --git a/moonscript/compile/statement.lua b/moonscript/compile/statement.lua index 2026a88f..eebb24a9 100644 --- a/moonscript/compile/statement.lua +++ b/moonscript/compile/statement.lua @@ -1,6 +1,3 @@ -local util = require("moonscript.util") -local reversed, unpack -reversed, unpack = util.reversed, util.unpack local ntype ntype = require("moonscript.types").ntype local concat, insert diff --git a/moonscript/compile/statement.moon b/moonscript/compile/statement.moon index e5c57403..45e9a489 100644 --- a/moonscript/compile/statement.moon +++ b/moonscript/compile/statement.moon @@ -1,7 +1,4 @@ -util = require "moonscript.util" - -import reversed, unpack from util import ntype from require "moonscript.types" import concat, insert from table diff --git a/moonscript/transform/comprehension.lua b/moonscript/transform/comprehension.lua index 1c1fb5f8..da33892d 100644 --- a/moonscript/transform/comprehension.lua +++ b/moonscript/transform/comprehension.lua @@ -1,15 +1,14 @@ local is_value is_value = require("moonscript.types").is_value -local reversed -reversed = require("moonscript.util").reversed local construct_comprehension construct_comprehension = function(inner, clauses) local current_stms = inner - for _, clause in reversed(clauses) do + for i = #clauses, 1, -1 do + local clause = clauses[i] local t = clause[1] local _exp_0 = t if "for" == _exp_0 then - local name, bounds + local _, name, bounds _, name, bounds = clause[1], clause[2], clause[3] current_stms = { "for", @@ -18,7 +17,7 @@ construct_comprehension = function(inner, clauses) current_stms } elseif "foreach" == _exp_0 then - local names, iter + local _, names, iter _, names, iter = clause[1], clause[2], clause[3] current_stms = { "foreach", @@ -29,7 +28,7 @@ construct_comprehension = function(inner, clauses) current_stms } elseif "when" == _exp_0 then - local cond + local _, cond _, cond = clause[1], clause[2] current_stms = { "if", diff --git a/moonscript/transform/comprehension.moon b/moonscript/transform/comprehension.moon index 61f9696f..a181a891 100644 --- a/moonscript/transform/comprehension.moon +++ b/moonscript/transform/comprehension.moon @@ -1,12 +1,12 @@ import is_value from require "moonscript.types" --- TODO: reversed unecessary -import reversed from require "moonscript.util" construct_comprehension = (inner, clauses) -> current_stms = inner - for _, clause in reversed clauses + for i=#clauses,1,-1 + clause = clauses[i] t = clause[1] + current_stms = switch t when "for" {_, name, bounds} = clause diff --git a/moonscript/util.lua b/moonscript/util.lua index cc41ebc3..bde0d576 100644 --- a/moonscript/util.lua +++ b/moonscript/util.lua @@ -60,14 +60,6 @@ get_closest_line = function(str, line_num) return line, line_num end end -local reversed -reversed = function(seq) - return coroutine.wrap(function() - for i = #seq, 1, -1 do - coroutine.yield(i, seq[i]) - end - end) -end local split split = function(str, delim) if str == "" then @@ -209,7 +201,6 @@ return { pos_to_line = pos_to_line, get_closest_line = get_closest_line, get_line = get_line, - reversed = reversed, trim = trim, split = split, dump = dump, diff --git a/moonscript/util.moon b/moonscript/util.moon index 8df3b538..ea7c8a5b 100644 --- a/moonscript/util.moon +++ b/moonscript/util.moon @@ -48,11 +48,6 @@ get_closest_line = (str, line_num) -> else line, line_num -reversed = (seq) -> - coroutine.wrap -> - for i=#seq,1,-1 - coroutine.yield i, seq[i] - split = (str, delim) -> return {} if str == "" str ..= delim @@ -136,7 +131,7 @@ safe_module = (name, tbl) -> } { - :moon, :pos_to_line, :get_closest_line, :get_line, :reversed, :trim, :split, - :dump, :debug_posmap, :getfenv, :setfenv, :get_options, :unpack, :safe_module + :moon, :pos_to_line, :get_closest_line, :get_line, :trim, :split, :dump, + :debug_posmap, :getfenv, :setfenv, :get_options, :unpack, :safe_module } From 76454f61ae005c7dceca3c04ef77b279da04ecab Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 6 Dec 2015 00:16:49 -0800 Subject: [PATCH 326/554] update rockspec --- moonscript-dev-1.rockspec | 1 + 1 file changed, 1 insertion(+) diff --git a/moonscript-dev-1.rockspec b/moonscript-dev-1.rockspec index 734ac3e1..b3ff2432 100644 --- a/moonscript-dev-1.rockspec +++ b/moonscript-dev-1.rockspec @@ -43,6 +43,7 @@ build = { ["moonscript.parse.util"] = "moonscript/parse/util.lua", ["moonscript.transform"] = "moonscript/transform.lua", ["moonscript.transform.accumulator"] = "moonscript/transform/accumulator.lua", + ["moonscript.transform.class"] = "moonscript/transform/class.lua", ["moonscript.transform.comprehension"] = "moonscript/transform/comprehension.lua", ["moonscript.transform.destructure"] = "moonscript/transform/destructure.lua", ["moonscript.transform.names"] = "moonscript/transform/names.lua", From 4b26091c9f476e9e12270501701c7139a4008e82 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 6 Dec 2015 02:05:47 -0800 Subject: [PATCH 327/554] change how super method name is set --- moonscript/compile/statement.moon | 2 +- moonscript/compile/value.lua | 12 ++++++++++-- moonscript/compile/value.moon | 8 ++++++-- moonscript/transform/class.lua | 29 ++++++++++++++++++++++++++--- moonscript/transform/class.moon | 20 +++++++++++++++++--- 5 files changed, 60 insertions(+), 11 deletions(-) diff --git a/moonscript/compile/statement.moon b/moonscript/compile/statement.moon index 45e9a489..bb80e969 100644 --- a/moonscript/compile/statement.moon +++ b/moonscript/compile/statement.moon @@ -27,7 +27,7 @@ import concat, insert from table _, names, values = unpack node undeclared = @declare names - declare = "local "..concat(undeclared, ", ") + declare = "local " .. concat(undeclared, ", ") has_fndef = false i = 1 diff --git a/moonscript/compile/value.lua b/moonscript/compile/value.lua index 82cc7304..af7320ea 100644 --- a/moonscript/compile/value.lua +++ b/moonscript/compile/value.lua @@ -17,6 +17,16 @@ local string_chars = { ["\n"] = "\\n" } return { + scoped = function(self, node) + local _, before, value, after + _, before, value, after = node[1], node[2], node[3], node[4] + _ = before and before:call(self) + do + local _with_0 = self:value(value) + _ = after and after:call(self) + return _with_0 + end + end, exp = function(self, node) local _comp _comp = function(i, value) @@ -248,9 +258,7 @@ return { else assign = self:line("[", _with_0:value(key), "]") end - _with_0:set("current_block", key) local out = self:line(assign, " = ", _with_0:value(value)) - _with_0:set("current_block", nil) return out else return self:line(_with_0:value(tuple[1])) diff --git a/moonscript/compile/value.moon b/moonscript/compile/value.moon index fb5c2253..193a4b5e 100644 --- a/moonscript/compile/value.moon +++ b/moonscript/compile/value.moon @@ -15,6 +15,12 @@ string_chars = { } { + scoped: (node) => + {_, before, value, after} = node + before and before\call @ + with @value value + after and after\call @ + -- list of values separated by binary operators exp: (node) => _comp = (i, value) -> @@ -146,9 +152,7 @@ string_chars = { else @line "[", \value(key), "]" - \set "current_block", key out = @line assign, " = ", \value(value) - \set "current_block", nil out else @line \value tuple[1] diff --git a/moonscript/transform/class.lua b/moonscript/transform/class.lua index a8ad78b8..1079dcdc 100644 --- a/moonscript/transform/class.lua +++ b/moonscript/transform/class.lua @@ -13,6 +13,21 @@ do local _obj_0 = require("moonscript.types") build, ntype, NOOP = _obj_0.build, _obj_0.ntype, _obj_0.NOOP end +local super_scope +super_scope = function(value, key) + local prev_method + return { + "scoped", + Run(function(self) + prev_method = self:get("current_method") + return self:set("current_method", key) + end), + value, + Run(function(self) + return self:set("current_method", prev_method) + end) + } +end return function(self, node, ret, parent_assign) local _, name, parent_val, body = unpack(node) if parent_val == "" then @@ -51,7 +66,12 @@ return function(self, node, ret, parent_assign) _continue_0 = true break else - _value_0 = tuple + local val + key, val = tuple[1], tuple[2] + _value_0 = { + key, + super_scope(val, key) + } end _accum_0[_len_0] = _value_0 _len_0 = _len_0 + 1 @@ -129,7 +149,10 @@ return function(self, node, ret, parent_assign) local cls = build.table({ { "__init", - constructor + super_scope(constructor, { + "key_literal", + "__init" + }) }, { "__base", @@ -304,7 +327,7 @@ return function(self, node, ret, parent_assign) local new_chain = relative_parent local _exp_1 = head[1] if "call" == _exp_1 then - local calling_name = block:get("current_block") + local calling_name = block:get("current_method") assert(calling_name, "missing calling name") chain_tail[1] = { "call", diff --git a/moonscript/transform/class.moon b/moonscript/transform/class.moon index 007baced..f75e4e5e 100644 --- a/moonscript/transform/class.moon +++ b/moonscript/transform/class.moon @@ -6,6 +6,19 @@ CONSTRUCTOR_NAME = "new" import insert from table import build, ntype, NOOP from require "moonscript.types" +super_scope = (value, key) -> + local prev_method + + { + "scoped", + Run => + prev_method = @get "current_method" + @set "current_method", key + value + Run => + @set "current_method", prev_method + } + (node, ret, parent_assign) => _, name, parent_val, body = unpack node parent_val = nil if parent_val == "" @@ -32,7 +45,8 @@ import build, ntype, NOOP from require "moonscript.types" constructor = tuple[2] continue else - tuple + {key, val} = tuple + {key, super_scope val, key} parent_cls_name = NameProxy "parent" base_name = NameProxy "base" @@ -77,7 +91,7 @@ import build, ntype, NOOP from require "moonscript.types" {"string", '"', flattened_name} cls = build.table { - {"__init", constructor} + {"__init", super_scope constructor, {"key_literal", "__init"}} {"__base", base_name} {"__name", real_name} -- "quote the string" parent_val and {"__parent", parent_cls_name} or nil @@ -173,7 +187,7 @@ import build, ntype, NOOP from require "moonscript.types" switch head[1] -- calling super, inject calling name and self into chain when "call" - calling_name = block\get"current_block" + calling_name = block\get "current_method" assert calling_name, "missing calling name" chain_tail[1] = {"call", {"self", unpack head[2]}} From 8f647cc743a90ceac8124e44aa02551159901bf8 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 6 Dec 2015 02:07:41 -0800 Subject: [PATCH 328/554] spec for testing super scope when inside table/function --- spec/inputs/class.moon | 10 +++++++++ spec/outputs/class.lua | 48 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/spec/inputs/class.moon b/spec/inputs/class.moon index ebcca20e..87eb866c 100644 --- a/spec/inputs/class.moon +++ b/spec/inputs/class.moon @@ -176,4 +176,14 @@ class Something class X new: hi + +-- + +class Cool extends Thing + dang: => + { + hello: -> super! + world: -> super.one + } + nil diff --git a/spec/outputs/class.lua b/spec/outputs/class.lua index 30180620..6f361f82 100644 --- a/spec/outputs/class.lua +++ b/spec/outputs/class.lua @@ -761,4 +761,52 @@ do _base_0.__class = _class_0 X = _class_0 end +do + local _class_0 + local _parent_0 = Thing + local _base_0 = { + dang = function(self) + return { + hello = function() + return _class_0.__parent.dang(self) + end, + world = function() + return _class_0.__parent.one + end + } + end + } + _base_0.__index = _base_0 + setmetatable(_base_0, _parent_0.__base) + _class_0 = setmetatable({ + __init = function(self, ...) + return _class_0.__parent.__init(self, ...) + end, + __base = _base_0, + __name = "Cool", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil then + local parent = rawget(cls, "__parent") + if parent then + return parent[name] + end + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Cool = _class_0 +end return nil \ No newline at end of file From 3be7be0166a31e24618efc25bb7c983111319c91 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 6 Dec 2015 10:42:21 -0800 Subject: [PATCH 329/554] extract super transform out --- moonscript/transform/class.lua | 152 +++++++++++++++++--------------- moonscript/transform/class.moon | 119 +++++++++++++------------ 2 files changed, 141 insertions(+), 130 deletions(-) diff --git a/moonscript/transform/class.lua b/moonscript/transform/class.lua index 1079dcdc..a7a6273f 100644 --- a/moonscript/transform/class.lua +++ b/moonscript/transform/class.lua @@ -13,14 +13,80 @@ do local _obj_0 = require("moonscript.types") build, ntype, NOOP = _obj_0.build, _obj_0.ntype, _obj_0.NOOP end +local transform_super +transform_super = function(cls_name, block, chain) + local relative_parent = { + "chain", + cls_name, + { + "dot", + "__parent" + } + } + if not (chain) then + return relative_parent + end + local chain_tail = { + unpack(chain, 3) + } + local head = chain_tail[1] + if head == nil then + return relative_parent + end + local new_chain = relative_parent + local _exp_0 = head[1] + if "call" == _exp_0 then + local calling_name = block:get("current_method") + assert(calling_name, "missing calling name") + chain_tail[1] = { + "call", + { + "self", + unpack(head[2]) + } + } + if ntype(calling_name) == "key_literal" then + insert(new_chain, { + "dot", + calling_name[2] + }) + else + insert(new_chain, { + "index", + calling_name + }) + end + elseif "colon" == _exp_0 then + local call = chain_tail[2] + if call and call[1] == "call" then + chain_tail[1] = { + "dot", + head[2] + } + chain_tail[2] = { + "call", + { + "self", + unpack(call[2]) + } + } + end + end + for _index_0 = 1, #chain_tail do + local item = chain_tail[_index_0] + insert(new_chain, item) + end + return new_chain +end local super_scope -super_scope = function(value, key) +super_scope = function(value, t, key) local prev_method return { "scoped", Run(function(self) prev_method = self:get("current_method") - return self:set("current_method", key) + self:set("current_method", key) + return self:set("super", t) end), value, Run(function(self) @@ -33,6 +99,14 @@ return function(self, node, ret, parent_assign) if parent_val == "" then parent_val = nil end + local parent_cls_name = NameProxy("parent") + local base_name = NameProxy("base") + local self_name = NameProxy("self") + local cls_name = NameProxy("class") + local cls_super + cls_super = function(...) + return transform_super(cls_name, ...) + end local statements = { } local properties = { } for _index_0 = 1, #body do @@ -70,7 +144,7 @@ return function(self, node, ret, parent_assign) key, val = tuple[1], tuple[2] _value_0 = { key, - super_scope(val, key) + super_scope(val, cls_super, key) } end _accum_0[_len_0] = _value_0 @@ -83,10 +157,6 @@ return function(self, node, ret, parent_assign) end properties = _accum_0 end - local parent_cls_name = NameProxy("parent") - local base_name = NameProxy("base") - local self_name = NameProxy("self") - local cls_name = NameProxy("class") if not (constructor) then if parent_val then constructor = build.fndef({ @@ -149,7 +219,7 @@ return function(self, node, ret, parent_assign) local cls = build.table({ { "__init", - super_scope(constructor, { + super_scope(constructor, cls_super, { "key_literal", "__init" }) @@ -303,72 +373,8 @@ return function(self, node, ret, parent_assign) local out_body = { Run(function(self) if name then - self:put_name(name) + return self:put_name(name) end - return self:set("super", function(block, chain) - local relative_parent = { - "chain", - cls_name, - { - "dot", - "__parent" - } - } - if not (chain) then - return relative_parent - end - local chain_tail = { - unpack(chain, 3) - } - local head = chain_tail[1] - if head == nil then - return relative_parent - end - local new_chain = relative_parent - local _exp_1 = head[1] - if "call" == _exp_1 then - local calling_name = block:get("current_method") - assert(calling_name, "missing calling name") - chain_tail[1] = { - "call", - { - "self", - unpack(head[2]) - } - } - if ntype(calling_name) == "key_literal" then - insert(new_chain, { - "dot", - calling_name[2] - }) - else - insert(new_chain, { - "index", - calling_name - }) - end - elseif "colon" == _exp_1 then - local call = chain_tail[2] - if call and call[1] == "call" then - chain_tail[1] = { - "dot", - head[2] - } - chain_tail[2] = { - "call", - { - "self", - unpack(call[2]) - } - } - end - end - for _index_0 = 1, #chain_tail do - local item = chain_tail[_index_0] - insert(new_chain, item) - end - return new_chain - end) end), { "declare", diff --git a/moonscript/transform/class.moon b/moonscript/transform/class.moon index f75e4e5e..6dd7099b 100644 --- a/moonscript/transform/class.moon +++ b/moonscript/transform/class.moon @@ -6,7 +6,58 @@ CONSTRUCTOR_NAME = "new" import insert from table import build, ntype, NOOP from require "moonscript.types" -super_scope = (value, key) -> +transform_super = (cls_name, block, chain) -> + relative_parent = { + "chain", + cls_name + {"dot", "__parent"} + } + + return relative_parent unless chain + + chain_tail = { unpack chain, 3 } + head = chain_tail[1] + + if head == nil + return relative_parent + + new_chain = relative_parent + + switch head[1] + -- calling super, inject calling name and self into chain + when "call" + calling_name = block\get "current_method" + assert calling_name, "missing calling name" + chain_tail[1] = {"call", {"self", unpack head[2]}} + + if ntype(calling_name) == "key_literal" + insert new_chain, {"dot", calling_name[2]} + else + insert new_chain, {"index", calling_name} + + -- colon call on super, replace class with self as first arg + when "colon" + call = chain_tail[2] + -- calling chain tail + if call and call[1] == "call" + chain_tail[1] = { + "dot" + head[2] + } + + chain_tail[2] = { + "call" + { + "self" + unpack call[2] + } + } + + insert new_chain, item for item in *chain_tail + new_chain + + +super_scope = (value, t, key) -> local prev_method { @@ -14,6 +65,7 @@ super_scope = (value, key) -> Run => prev_method = @get "current_method" @set "current_method", key + @set "super", t value Run => @set "current_method", prev_method @@ -23,6 +75,13 @@ super_scope = (value, key) -> _, name, parent_val, body = unpack node parent_val = nil if parent_val == "" + parent_cls_name = NameProxy "parent" + base_name = NameProxy "base" + self_name = NameProxy "self" + cls_name = NameProxy "class" + + cls_super = (...) -> transform_super cls_name, ... + -- split apart properties and statements statements = {} properties = {} @@ -46,12 +105,8 @@ super_scope = (value, key) -> continue else {key, val} = tuple - {key, super_scope val, key} + {key, super_scope val, cls_super, key} - parent_cls_name = NameProxy "parent" - base_name = NameProxy "base" - self_name = NameProxy "self" - cls_name = NameProxy "class" unless constructor constructor = if parent_val @@ -91,7 +146,7 @@ super_scope = (value, key) -> {"string", '"', flattened_name} cls = build.table { - {"__init", super_scope constructor, {"key_literal", "__init"}} + {"__init", super_scope constructor, cls_super, {"key_literal", "__init"}} {"__base", base_name} {"__name", real_name} -- "quote the string" parent_val and {"__parent", parent_cls_name} or nil @@ -167,56 +222,6 @@ super_scope = (value, key) -> -- make sure we don't assign the class to a local inside the do @put_name name if name - @set "super", (block, chain) -> - relative_parent = { - "chain", - cls_name - {"dot", "__parent"} - } - - return relative_parent unless chain - - chain_tail = { unpack chain, 3 } - head = chain_tail[1] - - if head == nil - return relative_parent - - new_chain = relative_parent - - switch head[1] - -- calling super, inject calling name and self into chain - when "call" - calling_name = block\get "current_method" - assert calling_name, "missing calling name" - chain_tail[1] = {"call", {"self", unpack head[2]}} - - if ntype(calling_name) == "key_literal" - insert new_chain, {"dot", calling_name[2]} - else - insert new_chain, {"index", calling_name} - - -- colon call on super, replace class with self as first arg - when "colon" - call = chain_tail[2] - -- calling chain tail - if call and call[1] == "call" - chain_tail[1] = { - "dot" - head[2] - } - - chain_tail[2] = { - "call" - { - "self" - unpack call[2] - } - } - - insert new_chain, item for item in *chain_tail - new_chain - {"declare", { cls_name }} {"declare_glob", "*"} From a9bb80159f68d1f54b7b6c7f50a4244bdaaa40ea Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 6 Dec 2015 11:05:34 -0800 Subject: [PATCH 330/554] super works inside class methods --- moonscript/transform/class.lua | 8 +++++++- moonscript/transform/class.moon | 4 +++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/moonscript/transform/class.lua b/moonscript/transform/class.lua index a7a6273f..3e480c26 100644 --- a/moonscript/transform/class.lua +++ b/moonscript/transform/class.lua @@ -118,7 +118,13 @@ return function(self, node, ret, parent_assign) for _index_1 = 2, #item do local tuple = item[_index_1] if ntype(tuple[1]) == "self" then - insert(statements, build.assign_one(unpack(tuple))) + local k, v + k, v = tuple[1], tuple[2] + v = super_scope(v, cls_super, { + "key_literal", + k[2] + }) + insert(statements, build.assign_one(k, v)) else insert(properties, tuple) end diff --git a/moonscript/transform/class.moon b/moonscript/transform/class.moon index 6dd7099b..729c47a9 100644 --- a/moonscript/transform/class.moon +++ b/moonscript/transform/class.moon @@ -92,7 +92,9 @@ super_scope = (value, t, key) -> when "props" for tuple in *item[2,] if ntype(tuple[1]) == "self" - insert statements, build.assign_one unpack tuple + {k,v} = tuple + v = super_scope v, cls_super, {"key_literal", k[2]} + insert statements, build.assign_one k, v else insert properties, tuple From 1bdcf26b08e9929a55ceb02e3b91fb02df8f93cc Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 6 Dec 2015 11:06:35 -0800 Subject: [PATCH 331/554] super scope test --- spec/inputs/class.moon | 9 +++++++++ spec/outputs/class.lua | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/spec/inputs/class.moon b/spec/inputs/class.moon index 87eb866c..27fde65b 100644 --- a/spec/inputs/class.moon +++ b/spec/inputs/class.moon @@ -186,4 +186,13 @@ class Cool extends Thing world: -> super.one } + +-- + +class Cool extends Thing + dang: do_something => + super! + + + nil diff --git a/spec/outputs/class.lua b/spec/outputs/class.lua index 6f361f82..e9ce06b6 100644 --- a/spec/outputs/class.lua +++ b/spec/outputs/class.lua @@ -809,4 +809,45 @@ do end Cool = _class_0 end +do + local _class_0 + local _parent_0 = Thing + local _base_0 = { + dang = do_something(function(self) + return _class_0.__parent.dang(self) + end) + } + _base_0.__index = _base_0 + setmetatable(_base_0, _parent_0.__base) + _class_0 = setmetatable({ + __init = function(self, ...) + return _class_0.__parent.__init(self, ...) + end, + __base = _base_0, + __name = "Cool", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil then + local parent = rawget(cls, "__parent") + if parent then + return parent[name] + end + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Cool = _class_0 +end return nil \ No newline at end of file From 7eb269b35ab55de10be054756dc4709244d07988 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 6 Dec 2015 11:22:40 -0800 Subject: [PATCH 332/554] add distinct class and instance super transformers --- moonscript/transform/class.lua | 21 ++++++++++++++++++--- moonscript/transform/class.moon | 14 +++++++++++--- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/moonscript/transform/class.lua b/moonscript/transform/class.lua index 3e480c26..f55dce00 100644 --- a/moonscript/transform/class.lua +++ b/moonscript/transform/class.lua @@ -13,8 +13,13 @@ do local _obj_0 = require("moonscript.types") build, ntype, NOOP = _obj_0.build, _obj_0.ntype, _obj_0.NOOP end +local unpack +unpack = require("moonscript.util").unpack local transform_super -transform_super = function(cls_name, block, chain) +transform_super = function(cls_name, on_base, block, chain) + if on_base == nil then + on_base = true + end local relative_parent = { "chain", cls_name, @@ -36,6 +41,12 @@ transform_super = function(cls_name, block, chain) local new_chain = relative_parent local _exp_0 = head[1] if "call" == _exp_0 then + if on_base then + insert(new_chain, { + "dot", + "__base" + }) + end local calling_name = block:get("current_method") assert(calling_name, "missing calling name") chain_tail[1] = { @@ -103,9 +114,13 @@ return function(self, node, ret, parent_assign) local base_name = NameProxy("base") local self_name = NameProxy("self") local cls_name = NameProxy("class") + local cls_instance_super + cls_instance_super = function(...) + return transform_super(cls_name, true, ...) + end local cls_super cls_super = function(...) - return transform_super(cls_name, ...) + return transform_super(cls_name, false, ...) end local statements = { } local properties = { } @@ -150,7 +165,7 @@ return function(self, node, ret, parent_assign) key, val = tuple[1], tuple[2] _value_0 = { key, - super_scope(val, cls_super, key) + super_scope(val, cls_instance_super, key) } end _accum_0[_len_0] = _value_0 diff --git a/moonscript/transform/class.moon b/moonscript/transform/class.moon index 729c47a9..2a952657 100644 --- a/moonscript/transform/class.moon +++ b/moonscript/transform/class.moon @@ -5,8 +5,9 @@ CONSTRUCTOR_NAME = "new" import insert from table import build, ntype, NOOP from require "moonscript.types" +import unpack from require "moonscript.util" -transform_super = (cls_name, block, chain) -> +transform_super = (cls_name, on_base=true, block, chain) -> relative_parent = { "chain", cls_name @@ -26,6 +27,9 @@ transform_super = (cls_name, block, chain) -> switch head[1] -- calling super, inject calling name and self into chain when "call" + if on_base + insert new_chain, {"dot", "__base"} + calling_name = block\get "current_method" assert calling_name, "missing calling name" chain_tail[1] = {"call", {"self", unpack head[2]}} @@ -80,7 +84,11 @@ super_scope = (value, t, key) -> self_name = NameProxy "self" cls_name = NameProxy "class" - cls_super = (...) -> transform_super cls_name, ... + -- super call on instance + cls_instance_super = (...) -> transform_super cls_name, true, ... + + -- super call on parent class + cls_super = (...) -> transform_super cls_name, false, ... -- split apart properties and statements statements = {} @@ -107,7 +115,7 @@ super_scope = (value, t, key) -> continue else {key, val} = tuple - {key, super_scope val, cls_super, key} + {key, super_scope val, cls_instance_super, key} unless constructor From 7aa63b2b61c90c26f1f742356fc28269978923eb Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 6 Dec 2015 11:24:42 -0800 Subject: [PATCH 333/554] update specs for new class super --- spec/inputs/class.moon | 19 +++++++++-- spec/outputs/class.lua | 74 ++++++++++++++++++++++++++++++++++++++---- 2 files changed, 84 insertions(+), 9 deletions(-) diff --git a/spec/inputs/class.moon b/spec/inputs/class.moon index 27fde65b..af03994b 100644 --- a/spec/inputs/class.moon +++ b/spec/inputs/class.moon @@ -186,13 +186,28 @@ class Cool extends Thing world: -> super.one } - -- -class Cool extends Thing +class Whack extends Thing dang: do_something => super! +--- + +class Wowha extends Thing + @butt: -> + super! + super.hello + super\hello! + super\hello + + @butt: cool { + -> + super! + super.hello + super\hello! + super\hello + } nil diff --git a/spec/outputs/class.lua b/spec/outputs/class.lua index e9ce06b6..aebacbda 100644 --- a/spec/outputs/class.lua +++ b/spec/outputs/class.lua @@ -126,7 +126,7 @@ do local _parent_0 = Hi local _base_0 = { cool = function(self) - return _class_0.__parent.cool(self, 120302) + return _class_0.__parent.__base.cool(self, 120302) end } _base_0.__index = _base_0 @@ -193,7 +193,7 @@ do local _parent_0 = Okay local _base_0 = { something = function(self) - _class_0.__parent.something(self, 1, 2, 3, 4) + _class_0.__parent.__base.something(self, 1, 2, 3, 4) _class_0.__parent.something(another_self, 1, 2, 3, 4) return assert(_class_0.__parent == Okay) end @@ -336,7 +336,7 @@ do local _class_0 local _base_0 = { hi = function(self) - _class_0.__parent.hi(self, 1, 2, 3, 4)(1, 2, 3, 4) + _class_0.__parent.__base.hi(self, 1, 2, 3, 4)(1, 2, 3, 4) _class_0.__parent.something(1, 2, 3, 4) local _ = _class_0.__parent.something(1, 2, 3, 4).world _class_0.__parent.yeah(self, "world").okay(hi, hi, hi) @@ -768,7 +768,7 @@ do dang = function(self) return { hello = function() - return _class_0.__parent.dang(self) + return _class_0.__parent.__base.dang(self) end, world = function() return _class_0.__parent.one @@ -814,7 +814,7 @@ do local _parent_0 = Thing local _base_0 = { dang = do_something(function(self) - return _class_0.__parent.dang(self) + return _class_0.__parent.__base.dang(self) end) } _base_0.__index = _base_0 @@ -824,7 +824,7 @@ do return _class_0.__parent.__init(self, ...) end, __base = _base_0, - __name = "Cool", + __name = "Whack", __parent = _parent_0 }, { __index = function(cls, name) @@ -848,6 +848,66 @@ do if _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end - Cool = _class_0 + Whack = _class_0 +end +do + local _class_0 + local _parent_0 = Thing + local _base_0 = { } + _base_0.__index = _base_0 + setmetatable(_base_0, _parent_0.__base) + _class_0 = setmetatable({ + __init = function(self, ...) + return _class_0.__parent.__init(self, ...) + end, + __base = _base_0, + __name = "Wowha", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil then + local parent = rawget(cls, "__parent") + if parent then + return parent[name] + end + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.butt = function() + _class_0.__parent.butt(self) + _ = _class_0.__parent.hello + _class_0.__parent.hello(self) + local _base_1 = _class_0.__parent + local _fn_0 = _base_1.hello + return function(...) + return _fn_0(self, ...) + end + end + self.butt = cool({ + function() + _class_0.__parent.butt(self) + _ = _class_0.__parent.hello + _class_0.__parent.hello(self) + local _base_1 = _class_0.__parent + local _fn_0 = _base_1.hello + return function(...) + return _fn_0(self, ...) + end + end + }) + if _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Wowha = _class_0 end return nil \ No newline at end of file From 92932584b4b367cc6e28c244e794f1c4d8d8c743 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 6 Dec 2015 11:31:40 -0800 Subject: [PATCH 334/554] add more super class specs --- moonscript/cmd/lint.lua | 4 +- spec/class_spec.moon | 282 ++++++++++++++++++++++++---------------- spec/inputs/class.moon | 2 +- spec/outputs/class.lua | 4 +- 4 files changed, 173 insertions(+), 119 deletions(-) diff --git a/moonscript/cmd/lint.lua b/moonscript/cmd/lint.lua index 50509e57..8f036ff1 100644 --- a/moonscript/cmd/lint.lua +++ b/moonscript/cmd/lint.lua @@ -121,11 +121,11 @@ do end, render = function(self, ...) self:lint_check_unused() - return _class_0.__parent.render(self, ...) + return _class_0.__parent.__base.render(self, ...) end, block = function(self, ...) do - local _with_0 = _class_0.__parent.block(self, ...) + local _with_0 = _class_0.__parent.__base.block(self, ...) _with_0.block = self.block _with_0.render = self.render _with_0.get_root_block = self.get_root_block diff --git a/spec/class_spec.moon b/spec/class_spec.moon index d21e8bff..e66eefac 100644 --- a/spec/class_spec.moon +++ b/spec/class_spec.moon @@ -40,61 +40,6 @@ describe "class", -> instance = Thing "color" assert.same instance\get_property!, "green" - it "should call super constructor", -> - class Base - new: (@property) => - - class Thing extends Base - new: (@name) => - super "name" - - instance = Thing "the_thing" - - assert.same instance.property, "name" - assert.same instance.name, "the_thing" - - it "should call super method", -> - class Base - _count: 111 - counter: => @_count - - class Thing extends Base - counter: => "%08d"\format super! - - instance = Thing! - assert.same instance\counter!, "00000111" - - it "should call other method from super", -> - class Base - _count: 111 - counter: => - @_count - - class Thing extends Base - other_method: => super\counter! - - instance = Thing! - assert.same instance\other_method!, 111 - - it "should get super class", -> - class Base - class Thing extends Base - get_super: => super - - instance = Thing! - assert.is_true instance\get_super! == Base - - it "should get a bound method from super", -> - class Base - count: 1 - get_count: => @count - - class Thing extends Base - get_count: => "this is wrong" - get_method: => super\get_count - - instance = Thing! - assert.same instance\get_method!!, 1 it "should have class properties", -> class Base @@ -151,86 +96,195 @@ describe "class", -> assert.same "hello", Thing.prop - it "class properties take precedence in super class over base", -> - class Thing - @prop: "hello" - prop: "world" + describe "super", -> + it "should call super constructor", -> + class Base + new: (@property) => - class OtherThing extends Thing + class Thing extends Base + new: (@name) => + super "name" - assert.same "hello", OtherThing.prop + instance = Thing "the_thing" - it "gets value from base in super class", -> - class Thing - prop: "world" + assert.same instance.property, "name" + assert.same instance.name, "the_thing" - class OtherThing extends Thing - assert.same "world", OtherThing.prop + it "should call super method", -> + class Base + _count: 111 + counter: => @_count - it "should let parent be replaced on class", -> - class A - @prop: "yeah" - cool: => 1234 - plain: => "a" + class Thing extends Base + counter: => "%08d"\format super! - class B - @prop: "okay" - cool: => 9999 - plain: => "b" + instance = Thing! + assert.same instance\counter!, "00000111" - class Thing extends A - cool: => - super! + 1 + it "should call other method from super", -> + class Base + _count: 111 + counter: => + @_count - get_super: => - super + class Thing extends Base + other_method: => super\counter! - instance = Thing! + instance = Thing! + assert.same instance\other_method!, 111 + + it "should get super class", -> + class Base + class Thing extends Base + get_super: => super + + instance = Thing! + assert.is_true instance\get_super! == Base + + it "should get a bound method from super", -> + class Base + count: 1 + get_count: => @count + + class Thing extends Base + get_count: => "this is wrong" + get_method: => super\get_count + + instance = Thing! + assert.same instance\get_method!!, 1 + + it "class properties take precedence in super class over base", -> + class Thing + @prop: "hello" + prop: "world" + + class OtherThing extends Thing + + assert.same "hello", OtherThing.prop + + it "gets value from base in super class", -> + class Thing + prop: "world" + + class OtherThing extends Thing + assert.same "world", OtherThing.prop + + it "should let parent be replaced on class", -> + class A + @prop: "yeah" + cool: => 1234 + plain: => "a" + + class B + @prop: "okay" + cool: => 9999 + plain: => "b" + + class Thing extends A + cool: => + super! + 1 + + get_super: => + super + + instance = Thing! + + assert.same "a", instance\plain! + assert.same 1235, instance\cool! + assert A == instance\get_super!, "expected super to be B" + + Thing.__parent = B + setmetatable Thing.__base, B.__base + + assert.same "b", instance\plain! + assert.same 10000, instance\cool! + assert B == instance\get_super!, "expected super to be B" + + it "should resolve many levels of super", -> + class One + a: => + 1 + + class Two extends One + a: => + super! + 2 + + class Three extends Two + a: => + super! + 3 + + i = Three! + + assert.same 6, i\a! + + + it "should resolve many levels of super with a gap", -> + class One + a: => + 1 + + class Two extends One + + class Three extends Two + a: => + super! + 3 + + class Four extends Three + a: => + super! + 4 + + i = Four! + + assert.same 8, i\a! + + + it "should call correct class/instance super methods", -> + class Base + doit: => + "instance" - assert.same "a", instance\plain! - assert.same 1235, instance\cool! - assert A == instance\get_super!, "expected super to be B" + @doit: => + "class" - Thing.__parent = B - setmetatable Thing.__base, B.__base + class One extends Base + doit: => super! + @doit: => super! - assert.same "b", instance\plain! - assert.same 10000, instance\cool! - assert B == instance\get_super!, "expected super to be B" + assert.same "instance", One!\doit! + assert.same "class", One\doit! - it "should resolve many levels of super", -> - class One - a: => - 1 - class Two extends One - a: => - super! + 2 + it "should resolve many levels of super on class methods", -> + class One + @a: => + 1 - class Three extends Two - a: => - super! + 3 + class Two extends One - i = Three! + class Three extends Two + @a: => + super! + 3 - assert.same 6, i\a! + class Four extends Three + @a: => + super! + 4 + assert.same 8, Four\a! - it "should resolve many levels of super with a gap", -> - class One - a: => - 1 + it "super should still work when method wrapped", -> + add_some = (opts) -> + => opts.amount + opts[1] @ - class Two extends One + class Base + value: => 1 - class Three extends Two - a: => - super! + 3 + class Sub extends Base + value: add_some { + amount: 12 + => + super! + 100 + } - class Four extends Three - a: => - super! + 4 + assert.same 1 + 100 + 12, Sub!\value! - i = Four! - assert.same 8, i\a! diff --git a/spec/inputs/class.moon b/spec/inputs/class.moon index af03994b..9a980557 100644 --- a/spec/inputs/class.moon +++ b/spec/inputs/class.moon @@ -202,7 +202,7 @@ class Wowha extends Thing super\hello - @butt: cool { + @zone: cool { -> super! super.hello diff --git a/spec/outputs/class.lua b/spec/outputs/class.lua index aebacbda..018760a0 100644 --- a/spec/outputs/class.lua +++ b/spec/outputs/class.lua @@ -893,9 +893,9 @@ do return _fn_0(self, ...) end end - self.butt = cool({ + self.zone = cool({ function() - _class_0.__parent.butt(self) + _class_0.__parent.zone(self) _ = _class_0.__parent.hello _class_0.__parent.hello(self) local _base_1 = _class_0.__parent From 232bad8fc312141fda7ee2565fad098f097e285a Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 6 Dec 2015 11:34:04 -0800 Subject: [PATCH 335/554] add ref to unpack everywhere --- moonscript/compile/statement.lua | 2 ++ moonscript/compile/statement.moon | 2 ++ moonscript/transform/statement.lua | 2 ++ moonscript/transform/statement.moon | 2 ++ moonscript/transform/value.lua | 2 ++ moonscript/transform/value.moon | 1 + 6 files changed, 11 insertions(+) diff --git a/moonscript/compile/statement.lua b/moonscript/compile/statement.lua index eebb24a9..8b250d54 100644 --- a/moonscript/compile/statement.lua +++ b/moonscript/compile/statement.lua @@ -5,6 +5,8 @@ do local _obj_0 = table concat, insert = _obj_0.concat, _obj_0.insert end +local unpack +unpack = require("moonscript.util").unpack return { raw = function(self, node) return self:add(node[2]) diff --git a/moonscript/compile/statement.moon b/moonscript/compile/statement.moon index bb80e969..bddd3dca 100644 --- a/moonscript/compile/statement.moon +++ b/moonscript/compile/statement.moon @@ -2,6 +2,8 @@ import ntype from require "moonscript.types" import concat, insert from table +import unpack from require "moonscript.util" + { raw: (node) => @add node[2] diff --git a/moonscript/transform/statement.lua b/moonscript/transform/statement.lua index f37a9d6f..efc0e723 100644 --- a/moonscript/transform/statement.lua +++ b/moonscript/transform/statement.lua @@ -15,6 +15,8 @@ insert = table.insert local destructure = require("moonscript.transform.destructure") local construct_comprehension construct_comprehension = require("moonscript.transform.comprehension").construct_comprehension +local unpack +unpack = require("moonscript.util").unpack local with_continue_listener with_continue_listener = function(body) local continue_name = nil diff --git a/moonscript/transform/statement.moon b/moonscript/transform/statement.moon index 7933c5fe..1d11560b 100644 --- a/moonscript/transform/statement.moon +++ b/moonscript/transform/statement.moon @@ -15,6 +15,8 @@ import insert from table destructure = require "moonscript.transform.destructure" import construct_comprehension from require "moonscript.transform.comprehension" +import unpack from require "moonscript.util" + with_continue_listener = (body) -> continue_name = nil diff --git a/moonscript/transform/value.lua b/moonscript/transform/value.lua index 159ae52a..50a49041 100644 --- a/moonscript/transform/value.lua +++ b/moonscript/transform/value.lua @@ -23,6 +23,8 @@ local construct_comprehension construct_comprehension = require("moonscript.transform.comprehension").construct_comprehension local insert insert = table.insert +local unpack +unpack = require("moonscript.util").unpack return Transformer({ ["for"] = default_accumulator, ["while"] = default_accumulator, diff --git a/moonscript/transform/value.moon b/moonscript/transform/value.moon index 7b415d6f..18d97a3c 100644 --- a/moonscript/transform/value.moon +++ b/moonscript/transform/value.moon @@ -10,6 +10,7 @@ import Run, transform_last_stm, implicitly_return, chain_is_stub from require "m import construct_comprehension from require "moonscript.transform.comprehension" import insert from table +import unpack from require "moonscript.util" Transformer { for: default_accumulator From caa724d0989958e0d20a19e51c68e4cfb00bb164 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 6 Dec 2015 12:03:19 -0800 Subject: [PATCH 336/554] more spec --- spec/class_spec.moon | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/spec/class_spec.moon b/spec/class_spec.moon index e66eefac..394c59b1 100644 --- a/spec/class_spec.moon +++ b/spec/class_spec.moon @@ -285,6 +285,13 @@ describe "class", -> super! + 100 } + class OtherSub extends Base + value: if true + => 5 + super! + else + => 2 + super! + assert.same 1 + 100 + 12, Sub!\value! + assert.same 6, OtherSub!\value! From 352130cdaed47045a76c8d2b4f55b67a9d47d26e Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 6 Dec 2015 12:03:23 -0800 Subject: [PATCH 337/554] start writing changelog --- CHANGELOG.md | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b78411af..c6a8d0ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,82 @@ +# MoonScript v0.4.0 (2015-12-06) + +## Changes to `super` + +`super` now looks up the parent method via the class reference, instead of a +(fixed) closure to the parent class. + +Given the following code: + +```moonscript +class MyThing extends OtherThing + the_method: => + super! +``` + +In the past `super` would compile to something like this: + +```lua +_parent_0.the_method(self) +``` + +Where `_parent_0` was an internal local variable that contains a reference to +the parent class. Because the reference to parent is an internal local +variable, you could never swap out the parent unless resorting to the debug +library. + +This version will compile to: + +```lua +_class_0.__parent.__base.the_method(self) +``` + +Where `_class_0` is an internal local variable that contains the current class (`MyThing`). + +Another difference is that the instance method is looked up on `__base` instead +of the class. The old variation would trigger the metamethod for looking up on +the instance, but a class method of the same name could conflict, take +precedence, and be retuned instead. By referencing `__base` directly we avoid +this issue. + +### Super on class methods + +`super` can now be used on class methods. It works exactly as you would expect. + +```moonscript +class MyThing extends OtherThing + @static_method: => + print super! +``` + +Calling `super` will compile to: + +```moonscript +_class_0.__parent.static_method(self) +``` + +### Improved scoping for super + +The scoping of super is more intelligent. You can warp your methods in other +code and `super` will still generate correctly. For example, syntax like this +will now work as expected: + +```moonscript +class Sub extends Base + value: if debugging + => super! + 100 + else + => super! + 10 + + other_value: some_decorator { + the_func: => + super! + } +``` + +`super` will refer to the lexically closest class declaration to find the name +of the method it should call on the parent. + # MoonScript v0.3.2 (2015-6-01) ## Bug Fixes From 23cd6f5571b6f326eb706d15cadbecc7cc9e7094 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 6 Dec 2015 12:04:00 -0800 Subject: [PATCH 338/554] increment version :fish: --- moonscript/version.lua | 2 +- moonscript/version.moon | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/moonscript/version.lua b/moonscript/version.lua index 352d7a98..45fa3c50 100644 --- a/moonscript/version.lua +++ b/moonscript/version.lua @@ -1,4 +1,4 @@ -local version = "0.3.2" +local version = "0.4.0" return { version = version, print_version = function() diff --git a/moonscript/version.moon b/moonscript/version.moon index 018d1c8c..6f665e26 100644 --- a/moonscript/version.moon +++ b/moonscript/version.moon @@ -1,5 +1,5 @@ -version = "0.3.2" +version = "0.4.0" { version: version, From 36e7eb1846c368d047ab26ad166f20fce558b07b Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 6 Dec 2015 12:18:16 -0800 Subject: [PATCH 339/554] more changelog updates --- CHANGELOG.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c6a8d0ac..d2c2cdb7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -77,6 +77,20 @@ class Sub extends Base `super` will refer to the lexically closest class declaration to find the name of the method it should call on the parent. +## Bug Fixes + +* Nested `with` blocks used incorrect ref (#214 by @geomaster) +* Lua quote string literals had wrong precedence (#200 by @nonchip) +* Returning from `with` block would generate two `return` statements (#208) +* Including `return` or `break` in a `continue` wrapped block would generate invalid code (#215 #190 #183) + +## Other + +* Refactor transformer out into multiple files +* `moon` command line script rewritten in MoonScript +* `moonscript.parse.build_grammar` function for getting new instance of parser grammar +* Chain AST updated to be simpler + # MoonScript v0.3.2 (2015-6-01) ## Bug Fixes From 3aac81533a1abfc9629c932da7326845d222b643 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 6 Dec 2015 17:24:44 -0800 Subject: [PATCH 340/554] add new build status image --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index bf5359ea..871b86aa 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,8 @@ [![MoonScript](http://leafo.net/dump/sailormoonscript.png)](http://moonscript.org) -[![Build Status](https://travis-ci.org/leafo/moonscript.svg?branch=master)](https://travis-ci.org/leafo/moonscript) +[![Build Status](https://travis-ci.org/leafo/moonscript.svg?branch=master)](https://travis-ci.org/leafo/moonscript) [![Build status](https://ci.appveyor.com/api/projects/status/f5prpi4wvytul290/branch/binaries?svg=true)](https://ci.appveyor.com/project/leafo/moonscript/branch/binaries) + MoonScript is a programmer friendly language that compiles into [Lua](http://www.lua.org/). It gives you the power of the fastest scripting From b129b00daf7cff3e45cd9ef3a87ed5bf02bf0ea3 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 6 Dec 2015 17:33:35 -0800 Subject: [PATCH 341/554] update to travis build scripts from https://github.com/moteus/lua-travis-example no sudo oops forgot to install lua busted stable? we will get there.. use stable loadkit --- .travis.yml | 23 +++++--- .travis/platform.sh | 15 ++++++ .travis/setenv_lua.sh | 3 ++ .travis/setup_lua.sh | 121 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 156 insertions(+), 6 deletions(-) create mode 100644 .travis/platform.sh create mode 100644 .travis/setenv_lua.sh create mode 100644 .travis/setup_lua.sh diff --git a/.travis.yml b/.travis.yml index e9e6313d..48d84c8c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,22 @@ language: c +sudo: false + +env: + global: + - LUAROCKS=2.2.2 + matrix: + - LUA=lua5.1 + - LUA=lua5.2 + - LUA=lua5.3 + - LUA=luajit2.1 # current head of 2.1 branch + +before_install: + - source .travis/setenv_lua.sh + install: - - sudo apt-get install luarocks - - mkdir -p ~/.luarocks - - echo 'rocks_servers = { "http://luarocks.org" }' > ~/.luarocks/config.lua - - sudo luarocks install https://luarocks.org/manifests/olivine-labs/busted-2.0.rc7-0.rockspec - - sudo luarocks install https://raw.githubusercontent.com/leafo/loadkit/master/loadkit-dev-1.rockspec - - sudo luarocks make + - luarocks install https://luarocks.org/manifests/olivine-labs/busted-2.0.rc11-0.rockspec + - luarocks install loadkit + - luarocks make script: busted diff --git a/.travis/platform.sh b/.travis/platform.sh new file mode 100644 index 00000000..7259a7d6 --- /dev/null +++ b/.travis/platform.sh @@ -0,0 +1,15 @@ +if [ -z "${PLATFORM:-}" ]; then + PLATFORM=$TRAVIS_OS_NAME; +fi + +if [ "$PLATFORM" == "osx" ]; then + PLATFORM="macosx"; +fi + +if [ -z "$PLATFORM" ]; then + if [ "$(uname)" == "Linux" ]; then + PLATFORM="linux"; + else + PLATFORM="macosx"; + fi; +fi diff --git a/.travis/setenv_lua.sh b/.travis/setenv_lua.sh new file mode 100644 index 00000000..8d8c8255 --- /dev/null +++ b/.travis/setenv_lua.sh @@ -0,0 +1,3 @@ +export PATH=${PATH}:$HOME/.lua:$HOME/.local/bin:${TRAVIS_BUILD_DIR}/install/luarocks/bin +bash .travis/setup_lua.sh +eval `$HOME/.lua/luarocks path` diff --git a/.travis/setup_lua.sh b/.travis/setup_lua.sh new file mode 100644 index 00000000..275b0ec5 --- /dev/null +++ b/.travis/setup_lua.sh @@ -0,0 +1,121 @@ +#! /bin/bash + +# A script for setting up environment for travis-ci testing. +# Sets up Lua and Luarocks. +# LUA must be "lua5.1", "lua5.2" or "luajit". +# luajit2.0 - master v2.0 +# luajit2.1 - master v2.1 + +set -eufo pipefail + +LUAJIT_BASE="LuaJIT-2.0.4" + +source .travis/platform.sh + +LUA_HOME_DIR=$TRAVIS_BUILD_DIR/install/lua + +LR_HOME_DIR=$TRAVIS_BUILD_DIR/install/luarocks + +mkdir $HOME/.lua + +LUAJIT="no" + +if [ "$PLATFORM" == "macosx" ]; then + if [ "$LUA" == "luajit" ]; then + LUAJIT="yes"; + fi + if [ "$LUA" == "luajit2.0" ]; then + LUAJIT="yes"; + fi + if [ "$LUA" == "luajit2.1" ]; then + LUAJIT="yes"; + fi; +elif [ "$(expr substr $LUA 1 6)" == "luajit" ]; then + LUAJIT="yes"; +fi + +mkdir -p "$LUA_HOME_DIR" + +if [ "$LUAJIT" == "yes" ]; then + + if [ "$LUA" == "luajit" ]; then + curl http://luajit.org/download/$LUAJIT_BASE.tar.gz | tar xz; + else + git clone http://luajit.org/git/luajit-2.0.git $LUAJIT_BASE; + fi + + cd $LUAJIT_BASE + + if [ "$LUA" == "luajit2.1" ]; then + git checkout v2.1; + # force the INSTALL_TNAME to be luajit + perl -i -pe 's/INSTALL_TNAME=.+/INSTALL_TNAME= luajit/' Makefile + fi + + make && make install PREFIX="$LUA_HOME_DIR" + + ln -s $LUA_HOME_DIR/bin/luajit $HOME/.lua/luajit + ln -s $LUA_HOME_DIR/bin/luajit $HOME/.lua/lua; + +else + + if [ "$LUA" == "lua5.1" ]; then + curl http://www.lua.org/ftp/lua-5.1.5.tar.gz | tar xz + cd lua-5.1.5; + elif [ "$LUA" == "lua5.2" ]; then + curl http://www.lua.org/ftp/lua-5.2.4.tar.gz | tar xz + cd lua-5.2.4; + elif [ "$LUA" == "lua5.3" ]; then + curl http://www.lua.org/ftp/lua-5.3.2.tar.gz | tar xz + cd lua-5.3.2; + fi + + # Build Lua without backwards compatibility for testing + perl -i -pe 's/-DLUA_COMPAT_(ALL|5_2)//' src/Makefile + make $PLATFORM + make INSTALL_TOP="$LUA_HOME_DIR" install; + + ln -s $LUA_HOME_DIR/bin/lua $HOME/.lua/lua + ln -s $LUA_HOME_DIR/bin/luac $HOME/.lua/luac; + +fi + +cd $TRAVIS_BUILD_DIR + +lua -v + +LUAROCKS_BASE=luarocks-$LUAROCKS + +curl --location http://luarocks.org/releases/$LUAROCKS_BASE.tar.gz | tar xz + +cd $LUAROCKS_BASE + +if [ "$LUA" == "luajit" ]; then + ./configure --lua-suffix=jit --with-lua-include="$LUA_HOME_DIR/include/luajit-2.0" --prefix="$LR_HOME_DIR"; +elif [ "$LUA" == "luajit2.0" ]; then + ./configure --lua-suffix=jit --with-lua-include="$LUA_HOME_DIR/include/luajit-2.0" --prefix="$LR_HOME_DIR"; +elif [ "$LUA" == "luajit2.1" ]; then + ./configure --lua-suffix=jit --with-lua-include="$LUA_HOME_DIR/include/luajit-2.1" --prefix="$LR_HOME_DIR"; +else + ./configure --with-lua="$LUA_HOME_DIR" --prefix="$LR_HOME_DIR" +fi + +make build && make install + +ln -s $LR_HOME_DIR/bin/luarocks $HOME/.lua/luarocks + +cd $TRAVIS_BUILD_DIR + +luarocks --version + +rm -rf $LUAROCKS_BASE + +if [ "$LUAJIT" == "yes" ]; then + rm -rf $LUAJIT_BASE; +elif [ "$LUA" == "lua5.1" ]; then + rm -rf lua-5.1.5; +elif [ "$LUA" == "lua5.2" ]; then + rm -rf lua-5.2.4; +elif [ "$LUA" == "lua5.3" ]; then + rm -rf lua-5.3.2; +fi From 9e606623656057b50d464259d4b7acdbada5aebd Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 6 Dec 2015 18:06:06 -0800 Subject: [PATCH 342/554] spec fixes for greater versions of lua --- moon/init.lua | 9 ++++++--- moon/init.moon | 4 +--- spec/comprehension_spec.moon | 2 ++ 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/moon/init.lua b/moon/init.lua index 0ca497c6..d4c24903 100644 --- a/moon/init.lua +++ b/moon/init.lua @@ -1,10 +1,13 @@ -local util = require("moonscript.util") local lua = { debug = debug, type = type } -local dump, p, is_object, type, debug, run_with_scope, bind_methods, defaultbl, extend, copy, mixin, mixin_object, mixin_table, fold -dump = util.dump +local getfenv, setfenv, dump +do + local _obj_0 = require("moonscript.util") + getfenv, setfenv, dump = _obj_0.getfenv, _obj_0.setfenv, _obj_0.dump +end +local p, is_object, type, debug, run_with_scope, bind_methods, defaultbl, extend, copy, mixin, mixin_object, mixin_table, fold p = function(...) return print(dump(...)) end diff --git a/moon/init.moon b/moon/init.moon index ef07bbaf..658d8867 100644 --- a/moon/init.moon +++ b/moon/init.moon @@ -1,11 +1,9 @@ -util = require "moonscript.util" lua = { :debug, :type } +import getfenv, setfenv, dump from require "moonscript.util" local * -dump = util.dump - p = (...) -> print dump ... diff --git a/spec/comprehension_spec.moon b/spec/comprehension_spec.moon index 2f07939d..d8823728 100644 --- a/spec/comprehension_spec.moon +++ b/spec/comprehension_spec.moon @@ -1,4 +1,6 @@ +import unpack from require "moonscript.util" + describe "comprehension", -> it "should double every number", -> input = {1,2,3,4,5,6} From a569774536a9e010ef50d7ab424a480b1fc51a46 Mon Sep 17 00:00:00 2001 From: nymphium Date: Wed, 9 Dec 2015 03:46:25 +0900 Subject: [PATCH 343/554] fix #191 benchmark failed --- moonscript/cmd/moonc.lua | 2 +- moonscript/cmd/moonc.moon | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/moonscript/cmd/moonc.lua b/moonscript/cmd/moonc.lua index eae86380..54600998 100644 --- a/moonscript/cmd/moonc.lua +++ b/moonscript/cmd/moonc.lua @@ -102,7 +102,7 @@ compile_file_text = function(text, opts) "Compile time\t" .. format_time(compile_time), "" }, "\n")) - return nil + return true end return code end diff --git a/moonscript/cmd/moonc.moon b/moonscript/cmd/moonc.moon index a680eaa7..b2e92e63 100644 --- a/moonscript/cmd/moonc.moon +++ b/moonscript/cmd/moonc.moon @@ -105,7 +105,7 @@ compile_file_text = (text, opts={}) -> "Compile time\t" .. format_time(compile_time), "" }, "\n" - return nil + return true code From a4bc557724cde78b0362f419ce6a0aaf708aa71d Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 27 Dec 2015 20:47:19 -0800 Subject: [PATCH 344/554] fix travis --- .travis/setup_lua.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.travis/setup_lua.sh b/.travis/setup_lua.sh index 275b0ec5..6dcc0c6e 100644 --- a/.travis/setup_lua.sh +++ b/.travis/setup_lua.sh @@ -8,7 +8,8 @@ set -eufo pipefail -LUAJIT_BASE="LuaJIT-2.0.4" +LUAJIT_VERSION="2.0.4" +LUAJIT_BASE="LuaJIT-$LUAJIT_VERSION" source .travis/platform.sh @@ -39,9 +40,9 @@ mkdir -p "$LUA_HOME_DIR" if [ "$LUAJIT" == "yes" ]; then if [ "$LUA" == "luajit" ]; then - curl http://luajit.org/download/$LUAJIT_BASE.tar.gz | tar xz; + curl --location https://github.com/LuaJIT/LuaJIT/archive/v$LUAJIT_VERSION.tar.gz | tar xz; else - git clone http://luajit.org/git/luajit-2.0.git $LUAJIT_BASE; + git clone https://github.com/LuaJIT/LuaJIT.git $LUAJIT_BASE; fi cd $LUAJIT_BASE From a9e0874a7aac427cb6ced5d39232e16ecef5c2f8 Mon Sep 17 00:00:00 2001 From: AlissaSquared Date: Sun, 27 Dec 2015 22:36:54 -0600 Subject: [PATCH 345/554] add lint option to watcher --- bin/moonc | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/bin/moonc b/bin/moonc index 5de57204..2d707678 100755 --- a/bin/moonc +++ b/bin/moonc @@ -264,6 +264,15 @@ local function create_watcher(files) end end +-- build function to check for lint or compile in watch +local check_compile_or_lint +if opts.l then + local lint = require "moonscript.cmd.lint" + check_compile_or_lint = lint.lint_file +else + check_compile_or_lint = compile_and_write +end + if opts.w then local watcher = create_watcher(files) -- catches interrupt error for ctl-c @@ -283,8 +292,14 @@ if opts.w then target = opts.o end - local success, err = compile_and_write(fname, target) - if not success then + local success, err = check_compile_or_lint(fname, target) + if opts.l then + if success then + io.stderr:write(success .. "\n\n") + elseif err then + io.stderr:write(fname .. "\n" .. err .. "\n\n") + end + elseif not success then io.stderr:write(table.concat({ "", "Error: " .. fname, @@ -300,8 +315,7 @@ if opts.w then elseif opts.l then for _, tuple in pairs(files) do local fname = tuple[1] - local lint = require "moonscript.cmd.lint" - local res, err = lint.lint_file(fname) + local res, err = check_compile_or_lint(fname) if res then io.stderr:write(res .. "\n\n") elseif err then From 47d94d5bb64aebd11b15c15f4e068cbd21992e33 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 27 Dec 2015 21:02:57 -0800 Subject: [PATCH 346/554] update preamble syntax --- docs/api.md | 11 ++++++----- docs/command_line.md | 11 ++++++----- docs/reference.md | 11 ++++++----- docs/standard_lib.md | 11 ++++++----- 4 files changed, 24 insertions(+), 20 deletions(-) diff --git a/docs/api.md b/docs/api.md index 367891af..a0aa7f55 100644 --- a/docs/api.md +++ b/docs/api.md @@ -1,8 +1,9 @@ -target: reference/api -template: reference -title: Compiler API -short_name: api --- +{ + target: "reference/api" + template: "reference" + title: "Compiler API" + short_name: "api" +} # MoonScript Compiler API diff --git a/docs/command_line.md b/docs/command_line.md index aac3e7bd..047a0ddd 100644 --- a/docs/command_line.md +++ b/docs/command_line.md @@ -1,8 +1,9 @@ -target: reference/command_line -template: reference -title: Command Line Tools -short_name: command_line --- +{ + target: "reference/command_line" + template: "reference" + title: "Command Line Tools" + short_name: "command_line" +} # Command Line Tools diff --git a/docs/reference.md b/docs/reference.md index 3a8e9872..960930a0 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -1,8 +1,9 @@ -target: reference/index -template: reference -title: Language Guide -short_name: lang --- +{ + target: "reference/index" + template: "reference" + title: "Language Guide" + short_name: "lang" +} MoonScript is a programming language that compiles to [Lua](http://www.lua.org). This guide expects the reader to have basic diff --git a/docs/standard_lib.md b/docs/standard_lib.md index 42cb7d4a..3a86a7b8 100644 --- a/docs/standard_lib.md +++ b/docs/standard_lib.md @@ -1,8 +1,9 @@ -target: reference/standard_lib -template: reference -title: Standard Library -short_name: stdlib --- +{ + target: "reference/standard_lib" + template: "reference" + title: "Standard Library" + short_name: "stdlib" +} The MoonScript installation comes with a small kernel of functions that can be used to perform various common things. From bbf5af654f63f052630ac700bba4f3d266feee90 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 27 Dec 2015 22:14:55 -0800 Subject: [PATCH 347/554] some style changes --- bin/moonc | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/bin/moonc b/bin/moonc index 2d707678..68a0284c 100755 --- a/bin/moonc +++ b/bin/moonc @@ -264,16 +264,17 @@ local function create_watcher(files) end end --- build function to check for lint or compile in watch -local check_compile_or_lint -if opts.l then - local lint = require "moonscript.cmd.lint" - check_compile_or_lint = lint.lint_file -else - check_compile_or_lint = compile_and_write -end if opts.w then + -- build function to check for lint or compile in watch + local handle_file + if opts.l then + local lint = require "moonscript.cmd.lint" + handle_file = lint.lint_file + else + handle_file = compile_and_write + end + local watcher = create_watcher(files) -- catches interrupt error for ctl-c local protected = function() @@ -292,7 +293,7 @@ if opts.w then target = opts.o end - local success, err = check_compile_or_lint(fname, target) + local success, err = handle_file(fname, target) if opts.l then if success then io.stderr:write(success .. "\n\n") @@ -313,9 +314,10 @@ if opts.w then io.stderr:write("\nQuitting...\n") elseif opts.l then + local lint = require "moonscript.cmd.lint" for _, tuple in pairs(files) do local fname = tuple[1] - local res, err = check_compile_or_lint(fname) + local res, err = lint.lint_file(fname) if res then io.stderr:write(res .. "\n\n") elseif err then From c5917c78b93fb7dfec5364cafd60ab66f7525d19 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 27 Dec 2015 22:30:37 -0800 Subject: [PATCH 348/554] misc --- moonscript/parse.moon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/moonscript/parse.moon b/moonscript/parse.moon index 0c6bc823..556f81da 100644 --- a/moonscript/parse.moon +++ b/moonscript/parse.moon @@ -282,7 +282,7 @@ build_grammar = wrap_env debug_grammar, (root) -> op"*" + op"^" + Ct(NameList) * (sym"=" * Ct(ExpListLow))^-1) / mark"export" - KeyValue: (sym":" * -SomeSpace * Name * lpeg.Cp()) / self_assign + Ct((KeyName + sym"[" * Exp * sym"]" + DoubleString + SingleString) * symx":" * (Exp + TableBlock + SpaceBreak^1 * Exp)) + KeyValue: (sym":" * -SomeSpace * Name * lpeg.Cp!) / self_assign + Ct((KeyName + sym"[" * Exp * sym"]" + DoubleString + SingleString) * symx":" * (Exp + TableBlock + SpaceBreak^1 * Exp)) KeyValueList: KeyValue * (sym"," * KeyValue)^0 KeyValueLine: CheckIndent * KeyValueList * sym","^-1 From fc77603156f75682cb059e3e244d58ab3c550175 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 27 Dec 2015 23:02:06 -0800 Subject: [PATCH 349/554] parser supports lulpeg, fixes #109 --- moonscript/parse.lua | 10 +++++----- moonscript/parse.moon | 14 ++++++-------- moonscript/parse/literals.lua | 7 ++++++- moonscript/parse/literals.moon | 6 +++++- 4 files changed, 22 insertions(+), 15 deletions(-) diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 072e4ef4..6e75c297 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -15,10 +15,10 @@ local wrap_env wrap_env = require("moonscript.parse.env").wrap_env local R, S, V, P, C, Ct, Cmt, Cg, Cb, Cc R, S, V, P, C, Ct, Cmt, Cg, Cb, Cc = lpeg.R, lpeg.S, lpeg.V, lpeg.P, lpeg.C, lpeg.Ct, lpeg.Cmt, lpeg.Cg, lpeg.Cb, lpeg.Cc -local White, Break, Stop, Comment, Space, SomeSpace, SpaceBreak, EmptyLine, AlphaNum, Num, Shebang, _Name +local White, Break, Stop, Comment, Space, SomeSpace, SpaceBreak, EmptyLine, AlphaNum, Num, Shebang, L, _Name do local _obj_0 = require("moonscript.parse.literals") - White, Break, Stop, Comment, Space, SomeSpace, SpaceBreak, EmptyLine, AlphaNum, Num, Shebang, _Name = _obj_0.White, _obj_0.Break, _obj_0.Stop, _obj_0.Comment, _obj_0.Space, _obj_0.SomeSpace, _obj_0.SpaceBreak, _obj_0.EmptyLine, _obj_0.AlphaNum, _obj_0.Num, _obj_0.Shebang, _obj_0.Name + White, Break, Stop, Comment, Space, SomeSpace, SpaceBreak, EmptyLine, AlphaNum, Num, Shebang, L, _Name = _obj_0.White, _obj_0.Break, _obj_0.Stop, _obj_0.Comment, _obj_0.Space, _obj_0.SomeSpace, _obj_0.SpaceBreak, _obj_0.EmptyLine, _obj_0.AlphaNum, _obj_0.Num, _obj_0.Shebang, _obj_0.L, _obj_0.Name end local SpaceName = Space * _Name Num = Space * (Num / function(v) @@ -110,10 +110,10 @@ local build_grammar = wrap_env(debug_grammar, function(root) File = Shebang ^ -1 * (Block + Ct("")), Block = Ct(Line * (Break ^ 1 * Line) ^ 0), CheckIndent = Cmt(Indent, check_indent), - Line = (CheckIndent * Statement + Space * #Stop), + Line = (CheckIndent * Statement + Space * L(Stop)), Statement = pos(Import + While + With + For + ForEach + Switch + Return + Local + Export + BreakLoop + Ct(ExpList) * (Update + Assign) ^ -1 / format_assign) * Space * ((key("if") * Exp * (key("else") * Exp) ^ -1 * Space / mark("if") + key("unless") * Exp / mark("unless") + CompInner / mark("comprehension")) * Space) ^ -1 / wrap_decorator, Body = Space ^ -1 * Break * EmptyLine ^ 0 * InBlock + Ct(Statement), - Advance = #Cmt(Indent, advance_indent), + Advance = L(Cmt(Indent, advance_indent)), PushIndent = Cmt(Indent, push_indent), PreventIndent = Cmt(Cc(-1), push_indent), PopIndent = Cmt("", pop_indent), @@ -170,7 +170,7 @@ local build_grammar = wrap_env(debug_grammar, function(root) ColonChainItem = symx("\\") * _Name / mark("colon"), ColonChain = ColonChainItem * (Invoke * ChainItems ^ -1) ^ -1, Slice = symx("[") * (SliceValue + Cc(1)) * sym(",") * (SliceValue + Cc("")) * (sym(",") * SliceValue) ^ -1 * sym("]") / mark("slice"), - Invoke = FnArgs / mark("call") + SingleString / wrap_func_arg + DoubleString / wrap_func_arg + #P("[") * LuaString / wrap_func_arg, + Invoke = FnArgs / mark("call") + SingleString / wrap_func_arg + DoubleString / wrap_func_arg + L(P("[")) * LuaString / wrap_func_arg, TableValue = KeyValue + Ct(Exp), TableLit = sym("{") * Ct(TableValueList ^ -1 * sym(",") ^ -1 * (SpaceBreak * TableLitLine * (sym(",") ^ -1 * SpaceBreak * TableLitLine) ^ 0 * sym(",") ^ -1) ^ -1) * White * sym("}") / mark("table"), TableValueList = TableValue * (sym(",") * TableValue) ^ 0, diff --git a/moonscript/parse.moon b/moonscript/parse.moon index c87cffad..87225a4c 100644 --- a/moonscript/parse.moon +++ b/moonscript/parse.moon @@ -3,11 +3,10 @@ lpeg = require "lpeg" lpeg.setmaxstack 10000 -- whoa - err_msg = "Failed to parse:%s\n [%d] >> %s" import Stack from require "moonscript.data" -import trim, pos_to_line, get_line from require"moonscript.util" +import trim, pos_to_line, get_line from require "moonscript.util" import unpack from require "moonscript.util" import wrap_env from require "moonscript.parse.env" @@ -17,11 +16,10 @@ import wrap_env from require "moonscript.parse.env" { :White, :Break, :Stop, :Comment, :Space, :SomeSpace, :SpaceBreak, :EmptyLine, - :AlphaNum, :Num, :Shebang + :AlphaNum, :Num, :Shebang, :L Name: _Name } = require "moonscript.parse.literals" - SpaceName = Space * _Name Num = Space * (Num / (v) -> {"number", v}) @@ -110,7 +108,7 @@ build_grammar = wrap_env debug_grammar, (root) -> File: Shebang^-1 * (Block + Ct"") Block: Ct(Line * (Break^1 * Line)^0) CheckIndent: Cmt(Indent, check_indent), -- validates line is in correct indent - Line: (CheckIndent * Statement + Space * #Stop) + Line: (CheckIndent * Statement + Space * L(Stop)) Statement: pos( Import + While + With + For + ForEach + Switch + Return + @@ -123,9 +121,9 @@ build_grammar = wrap_env debug_grammar, (root) -> CompInner / mark"comprehension" ) * Space)^-1 / wrap_decorator - Body: Space^-1 * Break * EmptyLine^0 * InBlock + Ct(Statement), -- either a statement, or an indented block + Body: Space^-1 * Break * EmptyLine^0 * InBlock + Ct(Statement) -- either a statement, or an indented block - Advance: #Cmt(Indent, advance_indent), -- Advances the indent, gives back whitespace for CheckIndent + Advance: L Cmt(Indent, advance_indent) -- Advances the indent, gives back whitespace for CheckIndent PushIndent: Cmt(Indent, push_indent) PreventIndent: Cmt(Cc(-1), push_indent) PopIndent: Cmt("", pop_indent) @@ -252,7 +250,7 @@ build_grammar = wrap_env debug_grammar, (root) -> Invoke: FnArgs / mark"call" + SingleString / wrap_func_arg + DoubleString / wrap_func_arg + - #P"[" * LuaString / wrap_func_arg + L(P"[") * LuaString / wrap_func_arg TableValue: KeyValue + Ct(Exp) diff --git a/moonscript/parse/literals.lua b/moonscript/parse/literals.lua index 61d6e2b8..1ad5aeb5 100644 --- a/moonscript/parse/literals.lua +++ b/moonscript/parse/literals.lua @@ -5,11 +5,15 @@ do local _obj_0 = require("lpeg") S, P, R, C = _obj_0.S, _obj_0.P, _obj_0.R, _obj_0.C end +local lpeg = require("lpeg") +local L = lpeg.luversion and lpeg.L or function(v) + return #v +end local White = S(" \t\r\n") ^ 0 local plain_space = S(" \t") ^ 0 local Break = P("\r") ^ -1 * P("\n") local Stop = Break + -1 -local Comment = P("--") * (1 - S("\r\n")) ^ 0 * #Stop +local Comment = P("--") * (1 - S("\r\n")) ^ 0 * L(Stop) local Space = plain_space * Comment ^ -1 local SomeSpace = S(" \t") ^ 1 * Comment ^ -1 local SpaceBreak = Space * Break @@ -19,6 +23,7 @@ local Name = C(R("az", "AZ", "__") * AlphaNum ^ 0) local Num = P("0x") * R("09", "af", "AF") ^ 1 * (S("uU") ^ -1 * S("lL") ^ 2) ^ -1 + R("09") ^ 1 * (S("uU") ^ -1 * S("lL") ^ 2) + (R("09") ^ 1 * (P(".") * R("09") ^ 1) ^ -1 + P(".") * R("09") ^ 1) * (S("eE") * P("-") ^ -1 * R("09") ^ 1) ^ -1 local Shebang = P("#!") * P(1 - Stop) ^ 0 return safe_module("moonscript.parse.literals", { + L = L, White = White, Break = Break, Stop = Stop, diff --git a/moonscript/parse/literals.moon b/moonscript/parse/literals.moon index 8f0d8cd6..5a4980f3 100644 --- a/moonscript/parse/literals.moon +++ b/moonscript/parse/literals.moon @@ -2,13 +2,16 @@ import safe_module from require "moonscript.util" import S, P, R, C from require "lpeg" +lpeg = require "lpeg" +L = lpeg.luversion and lpeg.L or (v) -> #v + White = S" \t\r\n"^0 plain_space = S" \t"^0 Break = P"\r"^-1 * P"\n" Stop = Break + -1 -Comment = P"--" * (1 - S"\r\n")^0 * #Stop +Comment = P"--" * (1 - S"\r\n")^0 * L(Stop) Space = plain_space * Comment^-1 SomeSpace = S" \t"^1 * Comment^-1 @@ -29,6 +32,7 @@ Num = P"0x" * R("09", "af", "AF")^1 * (S"uU"^-1 * S"lL"^2)^-1 + Shebang = P"#!" * P(1 - Stop)^0 safe_module "moonscript.parse.literals", { + :L :White, :Break, :Stop, :Comment, :Space, :SomeSpace, :SpaceBreak, :EmptyLine, :AlphaNum, :Name, :Num, :Shebang } From 1058593a3ee258296d976c10b82a26e0a449b37a Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Mon, 28 Dec 2015 02:12:50 -0800 Subject: [PATCH 350/554] remove scite extras, link to edit plugins fixes #198 --- README.md | 7 ++ extra/scintillua/README.md | 36 ------- extra/scintillua/lexers/moonscript.lua | 124 ------------------------ extra/scintillua/lexers/themes/moon.lua | 61 ------------ extra/scintillua/moonscript.properties | 11 --- 5 files changed, 7 insertions(+), 232 deletions(-) delete mode 100644 extra/scintillua/README.md delete mode 100644 extra/scintillua/lexers/moonscript.lua delete mode 100644 extra/scintillua/lexers/themes/moon.lua delete mode 100644 extra/scintillua/moonscript.properties diff --git a/README.md b/README.md index 871b86aa..b282f75d 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,13 @@ busted Writing specs is a bit more complicated. Check out [the spec writing guide](spec/README.md). + +## Editor Support + +* [Vim](https://github.com/leafo/moonscript-vim) +* [Textadept](https://github.com/leafo/moonscript-textadept) +* [Sublime/Textmate](https://github.com/leafo/moonscript-tmbundle) + ## License (MIT) Copyright (C) 2015 by Leaf Corcoran diff --git a/extra/scintillua/README.md b/extra/scintillua/README.md deleted file mode 100644 index ffeb9800..00000000 --- a/extra/scintillua/README.md +++ /dev/null @@ -1,36 +0,0 @@ -# MoonScript for [scintillua][1] - -MoonScript syntax file for [SciTE][2] written in Lua for [scintillua][1]. - -## Windows Binary - -Windows users can get a all-included package ready for MoonScript Development: - - - -If you already have a ScITE installation, or are on another platform, follow -the directions below. - -## Installation - -Install SciTE, then [install scintillua][1]. - -Put `moonscript.properties` in in your ScITE installation folder or user -properties folder. - -Copy the entire contents of the `lexers` folder in this repository into your -scintillua `lexers` folder. - -In your `lexers` folder edit `lpeg.properties`, add to the end: - - file.patterns.moonscript=*.moon - lexer.$(file.patterns.moonscript)=lpeg_moonscript - -Optionally, enable the Moon theme, find `lexer.peg.color.theme` in the same -file and change it to: - - lexer.lpeg.color.theme=moon - - [1]: http://foicica.com/scintillua/ "scintillua" - [2]: http://www.scintilla.org/SciTE.html "SciTE" - diff --git a/extra/scintillua/lexers/moonscript.lua b/extra/scintillua/lexers/moonscript.lua deleted file mode 100644 index 7a9e54b8..00000000 --- a/extra/scintillua/lexers/moonscript.lua +++ /dev/null @@ -1,124 +0,0 @@ --- Copyright 2006-2011 Mitchell mitchellcaladbolg.net. See LICENSE. --- Moonscript lexer by leaf corcoran - -local l = lexer -local token, word_match = l.token, l.word_match -local P, S, R = lpeg.P, lpeg.S, lpeg.R - -local M = { _NAME = 'moonscript' } - --- Whitespace. -local ws = token(l.WHITESPACE, l.space^1) - -local longstring = #('[[' + ('[' * P('=')^0 * '[')) -local longstring = longstring * P(function(input, index) - local level = input:match('^%[(=*)%[', index) - if level then - local _, stop = input:find(']'..level..']', index, true) - return stop and stop + 1 or #input + 1 - end -end) - --- Comments. -local line_comment = '--' * l.nonnewline^0 -local block_comment = '--' * longstring -local comment = token(l.COMMENT, block_comment + line_comment) - --- Strings. -local sq_str = l.delimited_range("'", '\\', true) -local dq_str = l.delimited_range('"', '\\', true) -local string = token(l.STRING, sq_str + dq_str + longstring) - --- Numbers. -local number = token(l.NUMBER, l.float + l.integer) - --- Keywords. -local keyword = token(l.KEYWORD, word_match { - 'return', 'break', 'for', 'while', - 'if', 'else', 'elseif', 'then', 'export', - 'import', 'from', 'with', 'in', 'and', - 'or', 'not', 'class', 'extends', 'super', 'do', - 'using', 'switch', 'when', -}) - -local special = token("special", word_match { "true", "false", "nil" }) - --- Functions. -local builtin = token(l.FUNCTION, word_match({ - "_G","_VERSION","assert","collectgarbage","dofile","error","getfenv","getmetatable","ipairs","load", - "loadfile","loadstring","module","next","pairs","pcall","print","rawequal","rawget","rawset","require", - "select","setfenv","setmetatable","tonumber","tostring","type","unpack","xpcall", - - "coroutine.create","coroutine.resume","coroutine.running","coroutine.status","coroutine.wrap","coroutine.yield", - - "debug.debug","debug.getfenv","debug.gethook","debug.getinfo","debug.getlocal","debug.getmetatable", - "debug.getregistry","debug.getupvalue","debug.setfenv","debug.sethook","debug.setlocal","debug.setmetatable", - "debug.setupvalue","debug.traceback", - - "io.close","io.flush","io.input","io.lines","io.open","io.output","io.popen","io.read","io.stderr","io.stdin", - "io.stdout","io.tmpfile","io.type","io.write", - - "math.abs","math.acos","math.asin","math.atan","math.atan2","math.ceil","math.cos","math.cosh","math.deg", - "math.exp","math.floor","math.fmod","math.frexp","math.huge","math.ldexp","math.log","math.log10","math.max", - "math.min","math.modf","math.pi","math.pow","math.rad","math.random","math.randomseed","math.sin","math.sinh", - "math.sqrt","math.tan","math.tanh", - - "os.clock","os.date","os.difftime","os.execute","os.exit","os.getenv","os.remove","os.rename","os.setlocale", - "os.time","os.tmpname", - - "package.cpath","package.loaded","package.loaders","package.loadlib","package.path","package.preload", - "package.seeall", - - "string.byte","string.char","string.dump","string.find","string.format","string.gmatch","string.gsub", - "string.len","string.lower","string.match","string.rep","string.reverse","string.sub","string.upper", - - "table.concat","table.insert","table.maxn","table.remove","table.sort" -}, "%.")) - --- Identifiers. -local identifier = token(l.IDENTIFIER, l.word) - -local fndef = token("fndef", P"->" + P"=>") -local err = token(l.ERROR, word_match { "function", "end" }) - --- Operators. -local symbol = token("symbol", S("(){}[]")) -local operator = token(l.OPERATOR, '~=' + S('+-*!\\/%^#=<>;:,.')) - --- self ref -local self_var = token("self_ref", "@" * l.word + "self") - -local proper_ident = token("proper_ident", R("AZ") * l.word) - -local tbl_key = token("tbl_key", l.word * ":" + ":" * l.word ) - -M._rules = { - { 'whitespace', ws }, - { 'error', err }, - { 'self', self_var }, - { 'special', special }, - { 'keyword', keyword }, - { 'builtin', builtin }, - { 'identifier', proper_ident + tbl_key + identifier }, - { 'comment', comment }, - { 'number', number }, - { 'string', string }, - { 'fndef', fndef }, - { 'symbol', symbol }, - { 'operator', operator }, - { 'any_char', l.any_char }, -} - -local style_special = { fore = l.colors.light_blue } -local style_fndef = { fore = l.colors.green } - -M._tokenstyles = { - { 'self_ref', style_special }, - { 'proper_ident', l.style_class }, - { 'fndef', style_fndef }, - { 'symbol', style_fndef }, - { 'special', style_special }, - { 'tbl_key', { fore = l.colors.red } }, -} - -return M diff --git a/extra/scintillua/lexers/themes/moon.lua b/extra/scintillua/lexers/themes/moon.lua deleted file mode 100644 index db8d7b26..00000000 --- a/extra/scintillua/lexers/themes/moon.lua +++ /dev/null @@ -1,61 +0,0 @@ --- Copyright 2006-2011 Mitchell mitchellcaladbolg.net. See LICENSE. --- moon lexer theme for Scintillua. - -module('lexer', package.seeall) - -colors = { - green = color('9F', 'FF', '98'), -- - blue = color('94', '95', 'FF'), -- - light_blue = color('98', 'D9', 'FF'), -- - red = color('FF', '98', '98'), -- - bright_red = color("F9", "26", "32"), -- - yellow = color('FF', 'E8', '98'), -- - teal = color('4D', '99', '99'), - white = color('FF', 'FF', 'FF'), -- - black = color('2E', '2E', '2E'), -- - grey = color('92', '92', '92'), -- - purple = color('CB', '98', 'FF'), -- - orange = color('FF', '92', '00'), -- - pink = color("ED", "4E", "78"), -- -} - -style_nothing = style { } -style_char = style { fore = colors.red, bold = true } -style_class = style { fore = colors.light_blue, bold = true } -style_comment = style { fore = colors.grey, } -style_constant = style { fore = colors.teal, bold = true } -style_definition = style { fore = colors.red, bold = true } -style_error = style { fore = colors.white, back = colors.bright_red, bold = true} -style_function = style { fore = colors.orange, bold = true } -style_keyword = style { fore = colors.purple, bold = true } -style_number = style { fore = colors.blue } -style_operator = style { fore = colors.red, bold = true } -style_string = style { fore = colors.yellow, bold = true } -style_preproc = style { fore = colors.light_blue } -style_tag = style { fore = colors.teal, bold = true } -style_type = style { fore = colors.green } -style_variable = style { fore = colors.white, italic = true } -style_embedded = style_tag..{ back = color('44', '44', '44') } -style_identifier = style_nothing - --- Default styles. -local font_face = '!Bitstream Vera Sans Mono' -local font_size = 12 -if WIN32 then - font_face = not GTK and 'Courier New' or '!Courier New' -elseif OSX then - font_face = '!Monaco' - font_size = 12 -end -style_default = style{ - font = font_face, - size = font_size, - fore = colors.white, - back = colors.black -} -style_line_number = style { fore = colors.black, back = colors.grey } -style_bracelight = style { fore = color('66', '99', 'FF'), bold = true } -style_bracebad = style { fore = color('FF', '66', '99'), bold = true } -style_controlchar = style_nothing -style_indentguide = style { fore = colors.grey, back = colors.white } -style_calltip = style { fore = colors.white, back = color('44', '44', '44') } diff --git a/extra/scintillua/moonscript.properties b/extra/scintillua/moonscript.properties deleted file mode 100644 index feff9333..00000000 --- a/extra/scintillua/moonscript.properties +++ /dev/null @@ -1,11 +0,0 @@ - -file.patterns.moon=*.moon -shbang.moon=moon -filter.moon=MoonScript (moon)|$(file.patterns.moon)| - -command.compile.*.moon=moonc "$(FileNameExt)" -command.go.*.moon=moon "$(FileNameExt)" - -tabsize=2 -indent.size=2 -use.tabs=0 \ No newline at end of file From 0262243136fdbb365c4b685202dba42b5452c828 Mon Sep 17 00:00:00 2001 From: AlissaSquared Date: Thu, 7 Jan 2016 17:37:47 -0600 Subject: [PATCH 351/554] Exit with status 1 on linting error --- bin/moonc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bin/moonc b/bin/moonc index 2d707678..99c056b4 100755 --- a/bin/moonc +++ b/bin/moonc @@ -313,15 +313,21 @@ if opts.w then io.stderr:write("\nQuitting...\n") elseif opts.l then + local has_linted_with_error; for _, tuple in pairs(files) do local fname = tuple[1] local res, err = check_compile_or_lint(fname) if res then + has_linted_with_error = true io.stderr:write(res .. "\n\n") elseif err then + has_linted_with_error = true io.stderr:write(fname .. "\n" .. err.. "\n\n") end end + if has_linted_with_error then + os.exit(1) + end else for _, tuple in ipairs(files) do local fname, target = util.unpack(tuple) From f4a2c6c46f0b185b4c188cc48b7346b663ace0c8 Mon Sep 17 00:00:00 2001 From: AlissaSquared Date: Sat, 9 Jan 2016 22:19:32 -0600 Subject: [PATCH 352/554] Added linting documentation --- docs/command_line.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/command_line.md b/docs/command_line.md index 047a0ddd..18743b23 100644 --- a/docs/command_line.md +++ b/docs/command_line.md @@ -134,11 +134,14 @@ A full list of flags can be seen by passing the `-h` or `--help` flag. `moonc` contains a [lint][1] tool for statically detecting potential problems with code. The linter has two tests: detects accessed global variables, -detect unused declared variables. +detect unused declared variables. If the linter detects any issues with a file, +the program will exit with a status of `1`. You can execute the linter with the `-l` flag. When the linting flag is provided only linting takes place and no compiled code is generated. +The linter is compatible with the watch mode (see above) for automatic linting + ```bash moonc -l file1.moon file2.moon ``` From 7758114e00c1269ef6741d6449184c0825043212 Mon Sep 17 00:00:00 2001 From: AlissaSquared Date: Sat, 9 Jan 2016 22:21:10 -0600 Subject: [PATCH 353/554] --- docs/command_line.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/command_line.md b/docs/command_line.md index 18743b23..31fe48ee 100644 --- a/docs/command_line.md +++ b/docs/command_line.md @@ -140,7 +140,7 @@ the program will exit with a status of `1`. You can execute the linter with the `-l` flag. When the linting flag is provided only linting takes place and no compiled code is generated. -The linter is compatible with the watch mode (see above) for automatic linting +The linter is compatible with the watch mode (see above) for automatic linting. ```bash moonc -l file1.moon file2.moon From b3a13435414a2592fc3d336508e89287437c54cd Mon Sep 17 00:00:00 2001 From: nymphium Date: Wed, 20 Jan 2016 02:26:50 +0900 Subject: [PATCH 354/554] refine makefile --- Makefile | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index 4435f99a..c63fba5a 100644 --- a/Makefile +++ b/Makefile @@ -1,16 +1,8 @@ -LUA ?= lua5.1 -LUAROCKS ?= luarocks - -ifneq ($(LUA),lua) - LUA_VERSION = $(shell echo $(LUA) | sed -e "s/lua\(.*\)/\1/") - LUAROCKS = luarocks-$(LUA_VERSION) - LUA_PATH_MAKE = $(shell echo "$$LUA_PATH" | sed -e "s/[0-9]\.[0-9]/$(LUA_VERSION)/g") - LUA_CPATH_MAKE = $(shell echo "$$LUA_CPATH" | sed -e "s/[0-9]\.[0-9]/$(LUA_VERSION)/g") -endif - -ifeq ($(LUA),luajit) - LUAROCKS = luarocks-5.1 -endif +LUA ?= lua5.1 +LUA_VERSION = $(shell $(LUA) -e 'print(_VERSION:match("%d%.%d"))') +LUAROCKS = luarocks-$(LUA_VERSION) +LUA_PATH_MAKE = $(shell $(LUAROCKS) path --lr-path) +LUA_CPATH_MAKE = $(shell $(LUAROCKS) path --lr-cpath) .PHONY: test local compile compile_system watch lint count show From e0c37ecb1516b5f381eb8c2937cfaf86d853fb15 Mon Sep 17 00:00:00 2001 From: nymphium Date: Wed, 20 Jan 2016 02:34:41 +0900 Subject: [PATCH 355/554] update for newest master branch From 2dc328bf5c1f0626c06146099a3b29236dbf49a8 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Mon, 28 Mar 2016 21:18:31 -0700 Subject: [PATCH 356/554] fix typo fixes --- docs/reference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference.md b/docs/reference.md index 960930a0..37e7871e 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -1234,7 +1234,7 @@ my_module = import \add from my_module -print add 22 -- equivalent to calling my_module\get 22 +print add 22 -- equivalent to calling my_module\add 22 ``` When handing multiple imports you can substitute the comma with a newline and From d8273d59855ec415718b5617f27beadb0ba322bd Mon Sep 17 00:00:00 2001 From: nymphium Date: Thu, 31 Mar 2016 00:16:51 +0900 Subject: [PATCH 357/554] Fix #255 : add unless - elseif --- moonscript/parse.lua | 2 +- moonscript/parse.moon | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 6e75c297..757519d6 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -132,7 +132,7 @@ local build_grammar = wrap_env(debug_grammar, function(root) SwitchElse = key("else") * Body / mark("else"), IfCond = Exp * Assign ^ -1 / format_single_assign, If = key("if") * IfCond * key("then") ^ -1 * Body * ((Break * CheckIndent) ^ -1 * EmptyLine ^ 0 * key("elseif") * pos(IfCond) * key("then") ^ -1 * Body / mark("elseif")) ^ 0 * ((Break * CheckIndent) ^ -1 * EmptyLine ^ 0 * key("else") * Body / mark("else")) ^ -1 / mark("if"), - Unless = key("unless") * IfCond * key("then") ^ -1 * Body * ((Break * CheckIndent) ^ -1 * EmptyLine ^ 0 * key("else") * Body / mark("else")) ^ -1 / mark("unless"), + Unless = key("unless") * IfCond * key("then") ^ -1 * Body * ((Break * CheckIndent) ^ -1 * EmptyLine ^ 0 * key("elseif") * pos(IfCond) * key("then") ^ -1 * Body / mark("elseif")) ^ 0 * ((Break * CheckIndent) ^ -1 * EmptyLine ^ 0 * key("else") * Body / mark("else")) ^ -1 / mark("unless"), While = key("while") * DisableDo * ensure(Exp, PopDo) * key("do") ^ -1 * Body / mark("while"), For = key("for") * DisableDo * ensure(Name * sym("=") * Ct(Exp * sym(",") * Exp * (sym(",") * Exp) ^ -1), PopDo) * key("do") ^ -1 * Body / mark("for"), ForEach = key("for") * Ct(AssignableNameList) * key("in") * DisableDo * ensure(Ct(sym("*") * Exp / mark("unpack") + ExpList), PopDo) * key("do") ^ -1 * Body / mark("foreach"), diff --git a/moonscript/parse.moon b/moonscript/parse.moon index 87225a4c..c7c836b5 100644 --- a/moonscript/parse.moon +++ b/moonscript/parse.moon @@ -155,6 +155,7 @@ build_grammar = wrap_env debug_grammar, (root) -> ((Break * CheckIndent)^-1 * EmptyLine^0 * key"else" * Body / mark"else")^-1 / mark"if" Unless: key"unless" * IfCond * key"then"^-1 * Body * + ((Break * CheckIndent)^-1 * EmptyLine^0 * key"elseif" * pos(IfCond) * key"then"^-1 * Body / mark"elseif")^0 * ((Break * CheckIndent)^-1 * EmptyLine^0 * key"else" * Body / mark"else")^-1 / mark"unless" While: key"while" * DisableDo * ensure(Exp, PopDo) * key"do"^-1 * Body / mark"while" From ca33e55ff3b20296a306135690e01f2d09cc7a19 Mon Sep 17 00:00:00 2001 From: nymphium Date: Thu, 31 Mar 2016 05:26:53 +0900 Subject: [PATCH 358/554] solve LUA_PATH overwrite problem --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index c63fba5a..d1c2b1f7 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ LUA ?= lua5.1 LUA_VERSION = $(shell $(LUA) -e 'print(_VERSION:match("%d%.%d"))') LUAROCKS = luarocks-$(LUA_VERSION) -LUA_PATH_MAKE = $(shell $(LUAROCKS) path --lr-path) -LUA_CPATH_MAKE = $(shell $(LUAROCKS) path --lr-cpath) +LUA_PATH_MAKE = $(shell $(LUAROCKS) path --lr-path);./?.lua;./?/init.lua +LUA_CPATH_MAKE = $(shell $(LUAROCKS) path --lr-cpath);./?.so .PHONY: test local compile compile_system watch lint count show From a841de51ab326101c6314b6b395e0cd1f70e85a3 Mon Sep 17 00:00:00 2001 From: nymphium Date: Thu, 31 Mar 2016 18:38:56 +0900 Subject: [PATCH 359/554] add spec --- spec/inputs/unless_else.moon | 5 +++++ spec/outputs/unless_else.lua | 7 +++++++ 2 files changed, 12 insertions(+) create mode 100644 spec/inputs/unless_else.moon create mode 100644 spec/outputs/unless_else.lua diff --git a/spec/inputs/unless_else.moon b/spec/inputs/unless_else.moon new file mode 100644 index 00000000..b421d4d0 --- /dev/null +++ b/spec/inputs/unless_else.moon @@ -0,0 +1,5 @@ +if a + unless b + print "hi" + elseif c + print "not hi" diff --git a/spec/outputs/unless_else.lua b/spec/outputs/unless_else.lua new file mode 100644 index 00000000..f05e7517 --- /dev/null +++ b/spec/outputs/unless_else.lua @@ -0,0 +1,7 @@ +if a then + if not (b) then + return print("hi") + elseif c then + return print("not hi") + end +end \ No newline at end of file From d85973411f7187da788191127d943fd681ff4813 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 7 Apr 2016 20:40:46 -0700 Subject: [PATCH 360/554] don't let unpack names reuse ones in scope, fixes #211, fixes #256 --- moonscript/transform/names.lua | 13 ++++++++++++- moonscript/transform/names.moon | 8 +++++++- moonscript/transform/statement.lua | 21 ++++++++++++++++++--- moonscript/transform/statement.moon | 6 ++++-- 4 files changed, 41 insertions(+), 7 deletions(-) diff --git a/moonscript/transform/names.lua b/moonscript/transform/names.lua index b498036e..f6af4c46 100644 --- a/moonscript/transform/names.lua +++ b/moonscript/transform/names.lua @@ -101,7 +101,18 @@ do _base_0.__class = _class_0 NameProxy = _class_0 end +local is_name_proxy +is_name_proxy = function(v) + if not (type(v) == "table") then + return false + end + local _exp_0 = v.__class + if LocalName == _exp_0 or NameProxy == _exp_0 then + return true + end +end return { NameProxy = NameProxy, - LocalName = LocalName + LocalName = LocalName, + is_name_proxy = is_name_proxy } diff --git a/moonscript/transform/names.moon b/moonscript/transform/names.moon index 220d862d..4af6aa0d 100644 --- a/moonscript/transform/names.moon +++ b/moonscript/transform/names.moon @@ -41,5 +41,11 @@ class NameProxy else ("name")\format @prefix +is_name_proxy = (v) -> + return false unless type(v) == "table" -{ :NameProxy, :LocalName } + switch v.__class + when LocalName, NameProxy + true + +{ :NameProxy, :LocalName, :is_name_proxy } diff --git a/moonscript/transform/statement.lua b/moonscript/transform/statement.lua index efc0e723..3e5986f4 100644 --- a/moonscript/transform/statement.lua +++ b/moonscript/transform/statement.lua @@ -1,7 +1,10 @@ local Transformer Transformer = require("moonscript.transform.transformer").Transformer -local NameProxy -NameProxy = require("moonscript.transform.names").NameProxy +local NameProxy, LocalName, is_name_proxy +do + local _obj_0 = require("moonscript.transform.names") + NameProxy, LocalName, is_name_proxy = _obj_0.NameProxy, _obj_0.LocalName, _obj_0.is_name_proxy +end local Run, transform_last_stm, implicitly_return, last_stm do local _obj_0 = require("moonscript.transform.statements") @@ -649,6 +652,18 @@ return Transformer({ } } end + local names + do + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = node.names + for _index_0 = 1, #_list_0 do + local n = _list_0[_index_0] + _accum_0[_len_0] = is_name_proxy(n) and n or LocalName(n) or n + _len_0 = _len_0 + 1 + end + names = _accum_0 + end return build.group({ list_name ~= list and build.assign_one(list_name, list) or NOOP, slice_var or NOOP, @@ -658,7 +673,7 @@ return Transformer({ body = { { "assign", - node.names, + names, { NameProxy.index(list_name, index_name) } diff --git a/moonscript/transform/statement.moon b/moonscript/transform/statement.moon index 1d11560b..50de0e0d 100644 --- a/moonscript/transform/statement.moon +++ b/moonscript/transform/statement.moon @@ -1,6 +1,6 @@ import Transformer from require "moonscript.transform.transformer" -import NameProxy from require "moonscript.transform.names" +import NameProxy, LocalName, is_name_proxy from require "moonscript.transform.names" import Run, transform_last_stm, implicitly_return, last_stm from require "moonscript.transform.statements" @@ -400,6 +400,8 @@ Transformer { else {1, {"length", list_name}} + names = [is_name_proxy(n) and n or LocalName(n) or n for n in *node.names] + return build.group { list_name != list and build.assign_one(list_name, list) or NOOP slice_var or NOOP @@ -407,7 +409,7 @@ Transformer { name: index_name bounds: bounds body: { - {"assign", node.names, { NameProxy.index list_name, index_name }} + {"assign", names, { NameProxy.index list_name, index_name }} build.group node.body } } From 716f2d53d621e2034ef3ea4ad6c6a89e0b6a6dd6 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 7 Apr 2016 20:41:47 -0700 Subject: [PATCH 361/554] rebuild specs --- spec/outputs/bubbling.lua | 2 +- spec/outputs/comprehension.lua | 4 ++-- spec/outputs/lists.lua | 8 ++++---- spec/outputs/loops.lua | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/spec/outputs/bubbling.lua b/spec/outputs/bubbling.lua index 247ff1c2..036d5fb7 100644 --- a/spec/outputs/bubbling.lua +++ b/spec/outputs/bubbling.lua @@ -78,7 +78,7 @@ do ... } for _index_0 = 1, #_list_0 do - x = _list_0[_index_0] + local x = _list_0[_index_0] _accum_0[_len_0] = x _len_0 = _len_0 + 1 end diff --git a/spec/outputs/comprehension.lua b/spec/outputs/comprehension.lua index 7512c5f3..ec3569a1 100644 --- a/spec/outputs/comprehension.lua +++ b/spec/outputs/comprehension.lua @@ -41,7 +41,7 @@ do local _tbl_0 = { } local _list_0 = yes for _index_0 = 1, #_list_0 do - x = _list_0[_index_0] + local x = _list_0[_index_0] local _key_0, _val_0 = unpack(x) _tbl_0[_key_0] = _val_0 end @@ -68,7 +68,7 @@ do } } for _index_0 = 1, #_list_0 do - x = _list_0[_index_0] + local x = _list_0[_index_0] local _key_0, _val_0 = unpack((function() local _accum_0 = { } local _len_0 = 1 diff --git a/spec/outputs/lists.lua b/spec/outputs/lists.lua index 4905ee0c..abb167eb 100644 --- a/spec/outputs/lists.lua +++ b/spec/outputs/lists.lua @@ -161,14 +161,14 @@ do local _accum_0 = { } local _len_0 = 1 for _index_0 = 1, #items do - x = items[_index_0] + local x = items[_index_0] _accum_0[_len_0] = x * 2 _len_0 = _len_0 + 1 end double = _accum_0 end for _index_0 = 1, #double do - x = double[_index_0] + local x = double[_index_0] print(x) end local cut @@ -176,7 +176,7 @@ do local _accum_0 = { } local _len_0 = 1 for _index_0 = 1, #items do - x = items[_index_0] + local x = items[_index_0] if x > 3 then _accum_0[_len_0] = x _len_0 = _len_0 + 1 @@ -189,7 +189,7 @@ do local _accum_0 = { } local _len_0 = 1 for _index_0 = 1, #items do - x = items[_index_0] + local x = items[_index_0] for _index_1 = 1, #items do local y = items[_index_1] _accum_0[_len_0] = x + y diff --git a/spec/outputs/loops.lua b/spec/outputs/loops.lua index db9aef33..57fe40be 100644 --- a/spec/outputs/loops.lua +++ b/spec/outputs/loops.lua @@ -62,7 +62,7 @@ do end x = function() for _index_0 = 1, #hello do - x = hello[_index_0] + local x = hello[_index_0] local _ = y end end From 33dfdad81e451eca659505d11ca3b4ada73e2040 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 7 Apr 2016 20:55:36 -0700 Subject: [PATCH 362/554] remove some duplicated rules #257 --- moonscript/parse.lua | 6 ++++-- moonscript/parse.moon | 10 ++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 757519d6..2ba504a3 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -131,8 +131,10 @@ local build_grammar = wrap_env(debug_grammar, function(root) SwitchCase = key("when") * Ct(ExpList) * key("then") ^ -1 * Body / mark("case"), SwitchElse = key("else") * Body / mark("else"), IfCond = Exp * Assign ^ -1 / format_single_assign, - If = key("if") * IfCond * key("then") ^ -1 * Body * ((Break * CheckIndent) ^ -1 * EmptyLine ^ 0 * key("elseif") * pos(IfCond) * key("then") ^ -1 * Body / mark("elseif")) ^ 0 * ((Break * CheckIndent) ^ -1 * EmptyLine ^ 0 * key("else") * Body / mark("else")) ^ -1 / mark("if"), - Unless = key("unless") * IfCond * key("then") ^ -1 * Body * ((Break * CheckIndent) ^ -1 * EmptyLine ^ 0 * key("elseif") * pos(IfCond) * key("then") ^ -1 * Body / mark("elseif")) ^ 0 * ((Break * CheckIndent) ^ -1 * EmptyLine ^ 0 * key("else") * Body / mark("else")) ^ -1 / mark("unless"), + IfElse = (Break * CheckIndent) ^ -1 * EmptyLine ^ 0 * key("else") * Body / mark("else"), + IfElseIf = (Break * CheckIndent) ^ -1 * EmptyLine ^ 0 * key("elseif") * pos(IfCond) * key("then") ^ -1 * Body / mark("elseif"), + If = key("if") * IfCond * key("then") ^ -1 * Body * IfElseIf ^ 0 * IfElse ^ -1 / mark("if"), + Unless = key("unless") * IfCond * key("then") ^ -1 * Body * IfElseIf ^ 0 * IfElse ^ -1 / mark("unless"), While = key("while") * DisableDo * ensure(Exp, PopDo) * key("do") ^ -1 * Body / mark("while"), For = key("for") * DisableDo * ensure(Name * sym("=") * Ct(Exp * sym(",") * Exp * (sym(",") * Exp) ^ -1), PopDo) * key("do") ^ -1 * Body / mark("for"), ForEach = key("for") * Ct(AssignableNameList) * key("in") * DisableDo * ensure(Ct(sym("*") * Exp / mark("unpack") + ExpList), PopDo) * key("do") ^ -1 * Body / mark("foreach"), diff --git a/moonscript/parse.moon b/moonscript/parse.moon index c7c836b5..f7d89268 100644 --- a/moonscript/parse.moon +++ b/moonscript/parse.moon @@ -150,13 +150,11 @@ build_grammar = wrap_env debug_grammar, (root) -> IfCond: Exp * Assign^-1 / format_single_assign - If: key"if" * IfCond * key"then"^-1 * Body * - ((Break * CheckIndent)^-1 * EmptyLine^0 * key"elseif" * pos(IfCond) * key"then"^-1 * Body / mark"elseif")^0 * - ((Break * CheckIndent)^-1 * EmptyLine^0 * key"else" * Body / mark"else")^-1 / mark"if" + IfElse: (Break * CheckIndent)^-1 * EmptyLine^0 * key"else" * Body / mark"else" + IfElseIf: (Break * CheckIndent)^-1 * EmptyLine^0 * key"elseif" * pos(IfCond) * key"then"^-1 * Body / mark"elseif" - Unless: key"unless" * IfCond * key"then"^-1 * Body * - ((Break * CheckIndent)^-1 * EmptyLine^0 * key"elseif" * pos(IfCond) * key"then"^-1 * Body / mark"elseif")^0 * - ((Break * CheckIndent)^-1 * EmptyLine^0 * key"else" * Body / mark"else")^-1 / mark"unless" + If: key"if" * IfCond * key"then"^-1 * Body * IfElseIf^0 * IfElse^-1 / mark"if" + Unless: key"unless" * IfCond * key"then"^-1 * Body * IfElseIf^0 * IfElse^-1 / mark"unless" While: key"while" * DisableDo * ensure(Exp, PopDo) * key"do"^-1 * Body / mark"while" From 4aa8603cf2da440b2017edd349af5324a82ca99f Mon Sep 17 00:00:00 2001 From: Ryan Rion Date: Wed, 13 Apr 2016 18:53:49 -0500 Subject: [PATCH 363/554] bin/moonc: fixes #259 when not using inotify --- bin/moonc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bin/moonc b/bin/moonc index 26c6873a..357a0f7b 100755 --- a/bin/moonc +++ b/bin/moonc @@ -247,8 +247,10 @@ local function create_watcher(files) for _, tuple in ipairs(files) do local file = tuple[1] local time = lfs.attributes(file, "modification") - if not mod_time[file] then - mod_time[file] = time + if not time then + mod_time[file] = nil -- file doesn't exist + elseif not mod_time[file] then + mod_time[file] = time -- new file created else if time ~= mod_time[file] then if time > mod_time[file] then From d573ba1953cac34db5548524de0b07c0697f40fe Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 13 Apr 2016 19:30:03 -0700 Subject: [PATCH 364/554] start moving watcher code out --- moonscript/cmd/watcher.lua | 149 ++++++++++++++++++++++++++++++++++++ moonscript/cmd/watcher.moon | 29 +++++++ spec/cmd_spec.moon | 18 ++++- 3 files changed, 194 insertions(+), 2 deletions(-) create mode 100644 moonscript/cmd/watcher.lua create mode 100644 moonscript/cmd/watcher.moon diff --git a/moonscript/cmd/watcher.lua b/moonscript/cmd/watcher.lua new file mode 100644 index 00000000..52be1d54 --- /dev/null +++ b/moonscript/cmd/watcher.lua @@ -0,0 +1,149 @@ +local remove_dupes +remove_dupes = function(list, key_fn) + local seen = { } + return (function() + local _accum_0 = { } + local _len_0 = 1 + for _index_0 = 1, #list do + local _continue_0 = false + repeat + local item = list[_index_0] + local key + if key_fn then + key = key_fn(item) + else + key = item + end + if seen[key] then + _continue_0 = true + break + end + seen[key] = true + local _value_0 = item + _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 + _continue_0 = true + until true + if not _continue_0 then + break + end + end + return _accum_0 + end)() +end +local Watcher +do + local _class_0 + local _base_0 = { } + _base_0.__index = _base_0 + _class_0 = setmetatable({ + __init = function(self, file_list) + self.file_list = file_list + end, + __base = _base_0, + __name = "Watcher" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + Watcher = _class_0 +end +local InotifyWacher +do + local _class_0 + local _parent_0 = Watcher + local _base_0 = { + get_dirs = function(self) + local parse_dir + parse_dir = require("moonscript.cmd.moonc").parse_dir + local dirs + do + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = self.file_list + for _index_0 = 1, #_list_0 do + local _des_0 = _list_0[_index_0] + local file_path + file_path = _des_0[1] + local dir = parse_dir(file_path) + if dir == "" then + dir = "./" + end + local _value_0 = dir + _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 + end + dirs = _accum_0 + end + return remove_dupes(dirs) + end + } + _base_0.__index = _base_0 + setmetatable(_base_0, _parent_0.__base) + _class_0 = setmetatable({ + __init = function(self, ...) + return _class_0.__parent.__init(self, ...) + end, + __base = _base_0, + __name = "InotifyWacher", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil then + local parent = rawget(cls, "__parent") + if parent then + return parent[name] + end + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.available = function(self) + return pcall(function() + return require("inotify") + end) + end + if _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + InotifyWacher = _class_0 +end +local SleepWatcher +do + local _class_0 + local _base_0 = { } + _base_0.__index = _base_0 + _class_0 = setmetatable({ + __init = function() end, + __base = _base_0, + __name = "SleepWatcher" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + SleepWatcher = _class_0 +end +return { + Watcher = Watcher, + SleepWatcher = SleepWatcher, + InotifyWacher = InotifyWacher +} diff --git a/moonscript/cmd/watcher.moon b/moonscript/cmd/watcher.moon new file mode 100644 index 00000000..afb5dd7c --- /dev/null +++ b/moonscript/cmd/watcher.moon @@ -0,0 +1,29 @@ +remove_dupes = (list, key_fn) -> + seen = {} + return for item in *list + key = if key_fn then key_fn item else item + continue if seen[key] + seen[key] = true + item + +-- files is a list of tuples, {source, target} +class Watcher + new: (@file_list) => + + +class InotifyWacher extends Watcher + @available: => + pcall -> require "inotify" + + get_dirs: => + import parse_dir from require "moonscript.cmd.moonc" + dirs = for {file_path} in *@file_list + dir = parse_dir file_path + dir = "./" if dir == "" + dir + + remove_dupes dirs + +class SleepWatcher + +{:Watcher, :SleepWatcher, :InotifyWacher} diff --git a/spec/cmd_spec.moon b/spec/cmd_spec.moon index 5e7b0dce..2ab51999 100644 --- a/spec/cmd_spec.moon +++ b/spec/cmd_spec.moon @@ -9,7 +9,7 @@ describe "moonc", -> dev_loaded = with_dev -> moonc = require "moonscript.cmd.moonc" - same = (fn, a, b)-> + same = (fn, a, b) -> assert.same b, fn a it "should normalize dir", -> @@ -18,7 +18,6 @@ describe "moonc", -> same moonc.normalize_dir, "", "/" -- wrong same moonc.normalize_dir, "hello", "hello/" - it "should parse dir", -> same moonc.parse_dir, "/hello/world/file", "/hello/world/" same moonc.parse_dir, "/hello/world/", "/hello/world/" @@ -63,6 +62,21 @@ describe "moonc", -> moonc.compile_file_text "print'hello'", fname: "test.moon" } + describe "watcher", -> + describe "inotify watcher", -> + it "gets dirs", -> + import InotifyWacher from require "moonscript.cmd.watcher" + watcher = InotifyWacher { + {"hello.moon", "hello.lua"} + {"cool/no.moon", "cool/no.lua"} + } + + assert.same { + "./" + "cool/" + }, watcher\get_dirs! + + describe "stubbed lfs", -> local dirs From c5cbf3315ef6b413bfac7c132e7d04b6b472b0ed Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 13 Apr 2016 19:30:11 -0700 Subject: [PATCH 365/554] rebuild --- moonscript/compile/statement.lua | 2 +- moonscript/dump.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/moonscript/compile/statement.lua b/moonscript/compile/statement.lua index 8b250d54..d2e9dee3 100644 --- a/moonscript/compile/statement.lua +++ b/moonscript/compile/statement.lua @@ -136,7 +136,7 @@ return { current = next end for _index_0 = 4, #node do - cond = node[_index_0] + local cond = node[_index_0] add_clause(cond) end return root diff --git a/moonscript/dump.lua b/moonscript/dump.lua index 8b69ec93..1496ed43 100644 --- a/moonscript/dump.lua +++ b/moonscript/dump.lua @@ -31,7 +31,7 @@ local tree tree = function(block) local _list_0 = block for _index_0 = 1, #_list_0 do - value = _list_0[_index_0] + local value = _list_0[_index_0] print(flat_value(value)) end end From fdfd314ebc38b7034a7fe956e8854fb35da8cd02 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 13 Apr 2016 19:47:27 -0700 Subject: [PATCH 366/554] move inotify watcher to library --- bin/moonc | 90 ++++++-------------- moonscript/cmd/watcher.moon | 29 ------- moonscript/cmd/{watcher.lua => watchers.lua} | 72 +++++++++++++++- moonscript/cmd/watchers.moon | 61 +++++++++++++ 4 files changed, 155 insertions(+), 97 deletions(-) delete mode 100644 moonscript/cmd/watcher.moon rename moonscript/cmd/{watcher.lua => watchers.lua} (61%) create mode 100644 moonscript/cmd/watchers.moon diff --git a/bin/moonc b/bin/moonc index 357a0f7b..bc246747 100755 --- a/bin/moonc +++ b/bin/moonc @@ -194,76 +194,38 @@ local function create_watcher(files) inotify = require "inotify" end) - if inotify then - local dirs = {} + local watchers = require("moonscript.cmd.watchers") - for _, tuple in ipairs(files) do - local dir = parse_dir(tuple[1]) - if dir == "" then - dir = "./" - end - table.insert(dirs, dir) - end - - dirs = remove_dups(dirs) - - return coroutine.wrap(function() - io.stderr:write(("%s with inotify [%s]"):format(msg, plural(#dirs, "dir")) .. "\n") - - local wd_table = {} - local handle = inotify.init() - for _, dir in ipairs(dirs) do - local wd = handle:addwatch(dir, inotify.IN_CLOSE_WRITE, inotify.IN_MOVED_TO) - wd_table[wd] = dir - end - - while true do - local events = handle:read() - if not events then - break - end + if watchers.InotifyWacher:available() then + return watchers.InotifyWacher(files):each_update() + end - for _, ev in ipairs(events) do - local fname = ev.name - if fname:match("%.moon$") then - local dir = wd_table[ev.wd] - if dir ~= "./" then - fname = dir .. fname + -- poll the filesystem instead + local sleep = get_sleep_func() + return coroutine.wrap(function() + io.stderr:write(("%s with polling [%s]"):format(msg, plural(#files, "file")) .. "\n") + + local mod_time = {} + while true do + for _, tuple in ipairs(files) do + local file = tuple[1] + local time = lfs.attributes(file, "modification") + if not time then + mod_time[file] = nil -- file doesn't exist + elseif not mod_time[file] then + mod_time[file] = time -- new file created + else + if time ~= mod_time[file] then + if time > mod_time[file] then + coroutine.yield(file) + mod_time[file] = time end - -- TODO: check to make sure the file was in the original set - coroutine.yield(fname) end end end - end) - else - -- poll the filesystem instead - local sleep = get_sleep_func() - return coroutine.wrap(function() - io.stderr:write(("%s with polling [%s]"):format(msg, plural(#files, "file")) .. "\n") - - local mod_time = {} - while true do - for _, tuple in ipairs(files) do - local file = tuple[1] - local time = lfs.attributes(file, "modification") - if not time then - mod_time[file] = nil -- file doesn't exist - elseif not mod_time[file] then - mod_time[file] = time -- new file created - else - if time ~= mod_time[file] then - if time > mod_time[file] then - coroutine.yield(file) - mod_time[file] = time - end - end - end - end - sleep(polling_rate) - end - end) - end + sleep(polling_rate) + end + end) end diff --git a/moonscript/cmd/watcher.moon b/moonscript/cmd/watcher.moon deleted file mode 100644 index afb5dd7c..00000000 --- a/moonscript/cmd/watcher.moon +++ /dev/null @@ -1,29 +0,0 @@ -remove_dupes = (list, key_fn) -> - seen = {} - return for item in *list - key = if key_fn then key_fn item else item - continue if seen[key] - seen[key] = true - item - --- files is a list of tuples, {source, target} -class Watcher - new: (@file_list) => - - -class InotifyWacher extends Watcher - @available: => - pcall -> require "inotify" - - get_dirs: => - import parse_dir from require "moonscript.cmd.moonc" - dirs = for {file_path} in *@file_list - dir = parse_dir file_path - dir = "./" if dir == "" - dir - - remove_dupes dirs - -class SleepWatcher - -{:Watcher, :SleepWatcher, :InotifyWacher} diff --git a/moonscript/cmd/watcher.lua b/moonscript/cmd/watchers.lua similarity index 61% rename from moonscript/cmd/watcher.lua rename to moonscript/cmd/watchers.lua index 52be1d54..21279baa 100644 --- a/moonscript/cmd/watcher.lua +++ b/moonscript/cmd/watchers.lua @@ -31,10 +31,16 @@ remove_dupes = function(list, key_fn) return _accum_0 end)() end +local plural +plural = function(count, word) + return tostring(count) .. " " .. tostring(word) .. tostring(count == 1 and "" or "s") +end local Watcher do local _class_0 - local _base_0 = { } + local _base_0 = { + start_msg = "Starting watch loop (Ctrl-C to exit)" + } _base_0.__index = _base_0 _class_0 = setmetatable({ __init = function(self, file_list) @@ -81,6 +87,46 @@ do dirs = _accum_0 end return remove_dupes(dirs) + end, + each_update = function(self) + return coroutine.wrap(function() + local dirs = self:get_dirs() + io.stderr:write(tostring(self.start_msg) .. " with inotify [" .. tostring(plural(#dirs, "dir")) .. "]\n") + local wd_table = { } + local inotify = require("inotify") + local handle = inotify.init() + for _index_0 = 1, #dirs do + local dir = dirs[_index_0] + local wd = handle:addwatch(dir, inotify.IN_CLOSE_WRITE, inotify.IN_MOVED_TO) + wd_table[wd] = dir + end + while true do + local events = handle:read() + if not (events) then + break + end + for _index_0 = 1, #events do + local _continue_0 = false + repeat + local ev = events[_index_0] + local fname = ev.name + if not (fname:match("%.moon$")) then + _continue_0 = true + break + end + local dir = wd_table[ev.wd] + if dir ~= "./" then + fname = dir .. fname + end + coroutine.yield(fname) + _continue_0 = true + until true + if not _continue_0 then + break + end + end + end + end) end } _base_0.__index = _base_0 @@ -125,14 +171,29 @@ end local SleepWatcher do local _class_0 + local _parent_0 = Watcher local _base_0 = { } _base_0.__index = _base_0 + setmetatable(_base_0, _parent_0.__base) _class_0 = setmetatable({ - __init = function() end, + __init = function(self, ...) + return _class_0.__parent.__init(self, ...) + end, __base = _base_0, - __name = "SleepWatcher" + __name = "SleepWatcher", + __parent = _parent_0 }, { - __index = _base_0, + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil then + local parent = rawget(cls, "__parent") + if parent then + return parent[name] + end + else + return val + end + end, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) @@ -140,6 +201,9 @@ do end }) _base_0.__class = _class_0 + if _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end SleepWatcher = _class_0 end return { diff --git a/moonscript/cmd/watchers.moon b/moonscript/cmd/watchers.moon new file mode 100644 index 00000000..6b91aa97 --- /dev/null +++ b/moonscript/cmd/watchers.moon @@ -0,0 +1,61 @@ +remove_dupes = (list, key_fn) -> + seen = {} + return for item in *list + key = if key_fn then key_fn item else item + continue if seen[key] + seen[key] = true + item + +plural = (count, word) -> + "#{count} #{word}#{count == 1 and "" or "s"}" + +-- files is a list of tuples, {source, target} +class Watcher + start_msg: "Starting watch loop (Ctrl-C to exit)" + new: (@file_list) => + +class InotifyWacher extends Watcher + @available: => + pcall -> require "inotify" + + get_dirs: => + import parse_dir from require "moonscript.cmd.moonc" + dirs = for {file_path} in *@file_list + dir = parse_dir file_path + dir = "./" if dir == "" + dir + + remove_dupes dirs + + -- creates an iterator that yields a file every time it's updated + -- TODO: detect when new files are added to directories + each_update: => + coroutine.wrap -> + dirs = @get_dirs! + + io.stderr\write "#{@start_msg} with inotify [#{plural #dirs, "dir"}]\n" + wd_table = {} + + inotify = require "inotify" + handle = inotify.init! + + for dir in *dirs + wd = handle\addwatch dir, inotify.IN_CLOSE_WRITE, inotify.IN_MOVED_TO + wd_table[wd] = dir + + while true + events = handle\read! + break unless events -- error? + + for ev in *events + fname = ev.name + continue unless fname\match "%.moon$" + dir = wd_table[ev.wd] + fname = dir .. fname if dir != "./" + + -- TODO: check to make sure the file was in the original set + coroutine.yield(fname) + +class SleepWatcher extends Watcher + +{:Watcher, :SleepWatcher, :InotifyWacher} From 1a776e30e0afbbe2b7f780d64c1405057c75b607 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 13 Apr 2016 19:47:37 -0700 Subject: [PATCH 367/554] make error message from loader more useful --- spec/helpers.moon | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spec/helpers.moon b/spec/helpers.moon index 42d578b3..45545b91 100644 --- a/spec/helpers.moon +++ b/spec/helpers.moon @@ -30,7 +30,8 @@ with_dev = (fn) -> mod\match("moon%.") or mod == "moon" if testable - dev_cache[mod] = assert(loadfile(assert loader mod))! + fname = assert loader(mod), "failed to find module: #{mod}" + dev_cache[mod] = assert(loadfile fname)! return dev_cache[mod] old_require mod From e251fa4a0241cce5220666c44daec80479c89f12 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 13 Apr 2016 19:49:16 -0700 Subject: [PATCH 368/554] misc --- moonscript/cmd/watchers.moon | 2 +- spec/cmd_spec.moon | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/moonscript/cmd/watchers.moon b/moonscript/cmd/watchers.moon index 6b91aa97..b9146bc6 100644 --- a/moonscript/cmd/watchers.moon +++ b/moonscript/cmd/watchers.moon @@ -54,7 +54,7 @@ class InotifyWacher extends Watcher fname = dir .. fname if dir != "./" -- TODO: check to make sure the file was in the original set - coroutine.yield(fname) + coroutine.yield fname class SleepWatcher extends Watcher diff --git a/spec/cmd_spec.moon b/spec/cmd_spec.moon index 2ab51999..63e88e35 100644 --- a/spec/cmd_spec.moon +++ b/spec/cmd_spec.moon @@ -65,7 +65,7 @@ describe "moonc", -> describe "watcher", -> describe "inotify watcher", -> it "gets dirs", -> - import InotifyWacher from require "moonscript.cmd.watcher" + import InotifyWacher from require "moonscript.cmd.watchers" watcher = InotifyWacher { {"hello.moon", "hello.lua"} {"cool/no.moon", "cool/no.lua"} From 4733598583c7a3f09da493d813028b054ffb7349 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 13 Apr 2016 20:05:51 -0700 Subject: [PATCH 369/554] move polling watcher --- bin/moonc | 59 +--------------------------------- moonscript-dev-1.rockspec | 1 + moonscript/cmd/watchers.lua | 62 ++++++++++++++++++++++++++++++++++-- moonscript/cmd/watchers.moon | 45 +++++++++++++++++++++++++- 4 files changed, 105 insertions(+), 62 deletions(-) diff --git a/bin/moonc b/bin/moonc index bc246747..30469377 100755 --- a/bin/moonc +++ b/bin/moonc @@ -9,8 +9,6 @@ local opts, ind = alt_getopt.get_opts(arg, "lvhwt:o:pTXb", { local read_stdin = arg[1] == "--" -local polling_rate = 1.0 - local help = [[Usage: %s [options] files... -h Print this message @@ -163,72 +161,17 @@ if opts.o and #files > 1 then print_help("-o can not be used with multiple input files") end -local function get_sleep_func() - local sleep - if not pcall(function() - local socket = require "socket" - sleep = socket.sleep - end) then - -- This is set by moonc.c in windows binaries - sleep = require("moonscript")._sleep - end - if not sleep then - error("Missing sleep function; install LuaSocket") - end - return sleep -end - -local function plural(count, word) - if count ~= 1 then - word = word .. "s" - end - return table.concat({count, word}, " ") -end - -- returns an iterator that returns files that have been updated local function create_watcher(files) - local msg = "Starting watch loop (Ctrl-C to exit)" - - local inotify - pcall(function() - inotify = require "inotify" - end) - local watchers = require("moonscript.cmd.watchers") if watchers.InotifyWacher:available() then return watchers.InotifyWacher(files):each_update() end - -- poll the filesystem instead - local sleep = get_sleep_func() - return coroutine.wrap(function() - io.stderr:write(("%s with polling [%s]"):format(msg, plural(#files, "file")) .. "\n") - - local mod_time = {} - while true do - for _, tuple in ipairs(files) do - local file = tuple[1] - local time = lfs.attributes(file, "modification") - if not time then - mod_time[file] = nil -- file doesn't exist - elseif not mod_time[file] then - mod_time[file] = time -- new file created - else - if time ~= mod_time[file] then - if time > mod_time[file] then - coroutine.yield(file) - mod_time[file] = time - end - end - end - end - sleep(polling_rate) - end - end) + return watchers.SleepWatcher(files):each_update() end - if opts.w then -- build function to check for lint or compile in watch local handle_file diff --git a/moonscript-dev-1.rockspec b/moonscript-dev-1.rockspec index b3ff2432..c4388d0a 100644 --- a/moonscript-dev-1.rockspec +++ b/moonscript-dev-1.rockspec @@ -30,6 +30,7 @@ build = { ["moonscript.cmd.coverage"] = "moonscript/cmd/coverage.lua", ["moonscript.cmd.lint"] = "moonscript/cmd/lint.lua", ["moonscript.cmd.moonc"] = "moonscript/cmd/moonc.lua", + ["moonscript.cmd.watchers"] = "moonscript/cmd/watchers.lua", ["moonscript.compile"] = "moonscript/compile.lua", ["moonscript.compile.statement"] = "moonscript/compile/statement.lua", ["moonscript.compile.value"] = "moonscript/compile/value.lua", diff --git a/moonscript/cmd/watchers.lua b/moonscript/cmd/watchers.lua index 21279baa..651011b2 100644 --- a/moonscript/cmd/watchers.lua +++ b/moonscript/cmd/watchers.lua @@ -39,7 +39,10 @@ local Watcher do local _class_0 local _base_0 = { - start_msg = "Starting watch loop (Ctrl-C to exit)" + start_msg = "Starting watch loop (Ctrl-C to exit)", + print_start = function(self, mode, misc) + return io.stderr:write(tostring(self.start_msg) .. " with " .. tostring(mode) .. " [" .. tostring(misc) .. "]\n") + end } _base_0.__index = _base_0 _class_0 = setmetatable({ @@ -91,7 +94,7 @@ do each_update = function(self) return coroutine.wrap(function() local dirs = self:get_dirs() - io.stderr:write(tostring(self.start_msg) .. " with inotify [" .. tostring(plural(#dirs, "dir")) .. "]\n") + self:print_start("inotify", plural(#dirs, "dir")) local wd_table = { } local inotify = require("inotify") local handle = inotify.init() @@ -172,7 +175,60 @@ local SleepWatcher do local _class_0 local _parent_0 = Watcher - local _base_0 = { } + local _base_0 = { + polling_rate = 1.0, + get_sleep_func = function(self) + local sleep + pcall(function() + sleep = require("socket").sleep + end) + sleep = sleep or require("moonscript")._sleep + if not (sleep) then + error("Missing sleep function; install LuaSocket") + end + return sleep + end, + each_update = function(self) + return coroutine.wrap(function() + local lfs = require("lfs") + local sleep = self:get_sleep_func() + self:print_start("polling", plural(#self.file_list, "files")) + local mod_time = { } + while true do + local _list_0 = self.file_list + for _index_0 = 1, #_list_0 do + local _continue_0 = false + repeat + local _des_0 = _list_0[_index_0] + local file + file = _des_0[1] + local time = lfs.attributes(file, "modification") + print(file, time) + if not (time) then + mod_time[file] = nil + _continue_0 = true + break + end + if not (mod_time[file]) then + mod_time[file] = time + _continue_0 = true + break + end + if time > mod_time[file] then + mod_time[file] = time + coroutine.yield(file) + end + _continue_0 = true + until true + if not _continue_0 then + break + end + end + sleep(self.polling_rate) + end + end) + end + } _base_0.__index = _base_0 setmetatable(_base_0, _parent_0.__base) _class_0 = setmetatable({ diff --git a/moonscript/cmd/watchers.moon b/moonscript/cmd/watchers.moon index b9146bc6..b021e80e 100644 --- a/moonscript/cmd/watchers.moon +++ b/moonscript/cmd/watchers.moon @@ -14,6 +14,9 @@ class Watcher start_msg: "Starting watch loop (Ctrl-C to exit)" new: (@file_list) => + print_start: (mode, misc) => + io.stderr\write "#{@start_msg} with #{mode} [#{misc}]\n" + class InotifyWacher extends Watcher @available: => pcall -> require "inotify" @@ -33,7 +36,8 @@ class InotifyWacher extends Watcher coroutine.wrap -> dirs = @get_dirs! - io.stderr\write "#{@start_msg} with inotify [#{plural #dirs, "dir"}]\n" + @print_start "inotify", plural #dirs, "dir" + wd_table = {} inotify = require "inotify" @@ -57,5 +61,44 @@ class InotifyWacher extends Watcher coroutine.yield fname class SleepWatcher extends Watcher + polling_rate: 1.0 + + -- the windows mooonscript binaries provide their own sleep function + get_sleep_func: => + local sleep + + pcall -> + sleep = require("socket").sleep + + -- TODO: this is also loading moonloader, which isn't intentional + sleep or= require("moonscript")._sleep + error "Missing sleep function; install LuaSocket" unless sleep + sleep + + each_update: => + coroutine.wrap -> + lfs = require "lfs" + sleep = @get_sleep_func! + + @print_start "polling", plural #@file_list, "files" + mod_time = {} + + while true + for {file} in *@file_list + time = lfs.attributes file, "modification" + print file, time + unless time -- file no longer exists + mod_time[file] = nil + continue + + unless mod_time[file] -- file time scanned + mod_time[file] = time + continue + + if time > mod_time[file] + mod_time[file] = time + coroutine.yield file + + sleep @polling_rate {:Watcher, :SleepWatcher, :InotifyWacher} From 94e5a32369b0cf3b7f943dcd92ef61aae329eb98 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 15 Apr 2016 23:51:27 -0700 Subject: [PATCH 370/554] start writing arg parser --- moonscript/cmd/args.lua | 43 ++++++++++++++++++++++++++++++++++++++++ moonscript/cmd/args.moon | 27 +++++++++++++++++++++++++ spec/cmd_spec.moon | 13 ++++++++++++ 3 files changed, 83 insertions(+) create mode 100644 moonscript/cmd/args.lua create mode 100644 moonscript/cmd/args.moon diff --git a/moonscript/cmd/args.lua b/moonscript/cmd/args.lua new file mode 100644 index 00000000..812b1ae6 --- /dev/null +++ b/moonscript/cmd/args.lua @@ -0,0 +1,43 @@ +local parse_arguments +parse_arguments = function(spec, args) + local out = { } + local remaining = { } + local last_flag = nil + for _index_0 = 1, #args do + local _continue_0 = false + repeat + local arg = args[_index_0] + if last_flag then + out[last_flag] = arg + _continue_0 = true + break + end + do + local flag = arg:match("-(%w+)") + if flag then + do + local short_name = spec[flag] + if short_name then + out[short_name] = true + else + for char in flag:gmatch(".") do + out[char] = true + end + end + end + _continue_0 = true + break + end + end + table.insert(remaining, arg) + _continue_0 = true + until true + if not _continue_0 then + break + end + end + return out, remaining +end +return { + parse_arguments = parse_arguments +} diff --git a/moonscript/cmd/args.moon b/moonscript/cmd/args.moon new file mode 100644 index 00000000..8ad0a9ca --- /dev/null +++ b/moonscript/cmd/args.moon @@ -0,0 +1,27 @@ + +parse_arguments = (spec, args) -> + out = {} + + remaining = {} + last_flag = nil + + for arg in *args + if last_flag + out[last_flag] = arg + continue + + if flag = arg\match "-(%w+)" + if short_name = spec[flag] + out[short_name] = true + else + for char in flag\gmatch "." + out[char] = true + continue + + table.insert remaining, arg + + out, remaining + + + +{:parse_arguments} diff --git a/spec/cmd_spec.moon b/spec/cmd_spec.moon index 63e88e35..6a117580 100644 --- a/spec/cmd_spec.moon +++ b/spec/cmd_spec.moon @@ -76,6 +76,19 @@ describe "moonc", -> "cool/" }, watcher\get_dirs! + describe "parse args", -> + import parse_arguments from require "moonscript.cmd.args" + + it "parses arguments", -> + out, res = parse_arguments { + print: "p" + }, {"hello", "word", "-gap"} + + assert.same { + g: true + a: true + p: true + }, out describe "stubbed lfs", -> local dirs From 7c17aefbc7e9dc13a03c1ef03400cfeff749cb1b Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 16 Apr 2016 23:58:36 -0700 Subject: [PATCH 371/554] parse spec --- moonscript/cmd/args.lua | 26 +++++++++++++++++++++++++- moonscript/cmd/args.moon | 22 +++++++++++++++++++++- spec/cmd_spec.moon | 12 +++++++++++- 3 files changed, 57 insertions(+), 3 deletions(-) diff --git a/moonscript/cmd/args.lua b/moonscript/cmd/args.lua index 812b1ae6..1f760000 100644 --- a/moonscript/cmd/args.lua +++ b/moonscript/cmd/args.lua @@ -1,5 +1,27 @@ +local parse_spec +parse_spec = function(spec) + local flags, words + if type(spec) == "table" then + flags, words = unpack(spec), spec + else + flags, words = spec, { } + end + assert("no flags for arguments") + local out = { } + for part in flags:gmatch("%w:?") do + if part:match(":$") then + out[part:sub(1, 1)] = { + value = true + } + else + out[part] = { } + end + end + return out +end local parse_arguments parse_arguments = function(spec, args) + spec = parse_spec(spec) local out = { } local remaining = { } local last_flag = nil @@ -7,6 +29,7 @@ parse_arguments = function(spec, args) local _continue_0 = false repeat local arg = args[_index_0] + local group = { } if last_flag then out[last_flag] = arg _continue_0 = true @@ -39,5 +62,6 @@ parse_arguments = function(spec, args) return out, remaining end return { - parse_arguments = parse_arguments + parse_arguments = parse_arguments, + parse_spec = parse_spec } diff --git a/moonscript/cmd/args.moon b/moonscript/cmd/args.moon index 8ad0a9ca..5bcbe37d 100644 --- a/moonscript/cmd/args.moon +++ b/moonscript/cmd/args.moon @@ -1,11 +1,31 @@ +parse_spec = (spec) -> + flags, words = if type(spec) == "table" + unpack(spec), spec + else + spec, {} + + assert "no flags for arguments" + + out = {} + for part in flags\gmatch "%w:?" + if part\match ":$" + out[part\sub 1,1] = { value: true } + else + out[part] = {} + + out + parse_arguments = (spec, args) -> + spec = parse_spec spec + out = {} remaining = {} last_flag = nil for arg in *args + group = {} if last_flag out[last_flag] = arg continue @@ -24,4 +44,4 @@ parse_arguments = (spec, args) -> -{:parse_arguments} +{ :parse_arguments, :parse_spec } diff --git a/spec/cmd_spec.moon b/spec/cmd_spec.moon index 6a117580..039973d5 100644 --- a/spec/cmd_spec.moon +++ b/spec/cmd_spec.moon @@ -77,10 +77,20 @@ describe "moonc", -> }, watcher\get_dirs! describe "parse args", -> - import parse_arguments from require "moonscript.cmd.args" + it "parses spec", -> + import parse_spec from require "moonscript.cmd.args" + spec = parse_spec "lt:o:X" + assert.same { + X: {} + o: {value: true} + t: {value: true} + l: {} + }, spec it "parses arguments", -> + import parse_arguments from require "moonscript.cmd.args" out, res = parse_arguments { + "ga:p" print: "p" }, {"hello", "word", "-gap"} From b2df8e6fc0fdc0ae7d07de5eba93f64cbb5c18f1 Mon Sep 17 00:00:00 2001 From: Ryan Rion Date: Sat, 30 Apr 2016 16:17:38 -0500 Subject: [PATCH 372/554] docs/api.md: Fix typo (finder => finer) (#268) --- docs/api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api.md b/docs/api.md index a0aa7f55..c59f6f70 100644 --- a/docs/api.md +++ b/docs/api.md @@ -98,7 +98,7 @@ is a character offset from the original MoonScript source. ## Programmatically Compiling -If you need finder grained control over the compilation process you can use the +If you need finer grained control over the compilation process you can use the raw parse and compile modules. Parsing converts a string of MoonScript into an abstract syntax tree. Compiling From 9302ef965724f77d05d7bc9eb21cea2d21b15094 Mon Sep 17 00:00:00 2001 From: Ryan Rion Date: Mon, 2 May 2016 19:55:15 -0500 Subject: [PATCH 373/554] moonscript/cmd/args.moon: fix `unpack()` Lua 5.2+ (#269) --- moonscript/cmd/args.lua | 2 ++ moonscript/cmd/args.moon | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/moonscript/cmd/args.lua b/moonscript/cmd/args.lua index 1f760000..68b06fdc 100644 --- a/moonscript/cmd/args.lua +++ b/moonscript/cmd/args.lua @@ -1,3 +1,5 @@ +local unpack +unpack = require("moonscript.util").unpack local parse_spec parse_spec = function(spec) local flags, words diff --git a/moonscript/cmd/args.moon b/moonscript/cmd/args.moon index 5bcbe37d..ac65c0e3 100644 --- a/moonscript/cmd/args.moon +++ b/moonscript/cmd/args.moon @@ -1,4 +1,4 @@ - +import unpack from require "moonscript.util" parse_spec = (spec) -> flags, words = if type(spec) == "table" unpack(spec), spec From 2d96e11ed344fbfc304acb7e42a011994833b9e7 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 13 Jul 2016 10:19:30 -0700 Subject: [PATCH 374/554] use most recent busted fixes #278 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 48d84c8c..11808bda 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,7 +15,7 @@ before_install: - source .travis/setenv_lua.sh install: - - luarocks install https://luarocks.org/manifests/olivine-labs/busted-2.0.rc11-0.rockspec + - luarocks install busted - luarocks install loadkit - luarocks make From c49fdca7aa7165040a6a3e94f0a1721c618a498d Mon Sep 17 00:00:00 2001 From: Gskartwii Date: Sun, 25 Sep 2016 20:18:42 +0300 Subject: [PATCH 375/554] Ignore directories named *.moon (#290) --- bin/moonc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/bin/moonc b/bin/moonc index 30469377..dfd56969 100755 --- a/bin/moonc +++ b/bin/moonc @@ -70,9 +70,7 @@ local function scan_directory(root, collected) if lfs.attributes(full_path, "mode") == "directory" then scan_directory(full_path, collected) - end - - if fname:match("%.moon$") then + elseif fname:match("%.moon$") then table.insert(collected, full_path) end end From 32d650a5ff91409e5b7ec0991db228857016f7e9 Mon Sep 17 00:00:00 2001 From: Jon Allen Date: Sun, 25 Sep 2016 12:21:34 -0500 Subject: [PATCH 376/554] switched the alt_getopt module import to work with newer versions of lua (#289) --- bin/moon | 2 +- bin/moon.moon | 2 +- bin/splat.moon | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bin/moon b/bin/moon index a4892bd3..9b7593ba 100755 --- a/bin/moon +++ b/bin/moon @@ -1,5 +1,5 @@ #!/usr/bin/env lua -require("alt_getopt") +local alt_getopt = require("alt_getopt") local moonscript = require("moonscript.base") local util = require("moonscript.util") local errors = require("moonscript.errors") diff --git a/bin/moon.moon b/bin/moon.moon index 853cf19b..eb36eab5 100644 --- a/bin/moon.moon +++ b/bin/moon.moon @@ -1,5 +1,5 @@ -require "alt_getopt" +alt_getopt = require "alt_getopt" moonscript = require "moonscript.base" util = require "moonscript.util" diff --git a/bin/splat.moon b/bin/splat.moon index 506a54ae..df523c14 100755 --- a/bin/splat.moon +++ b/bin/splat.moon @@ -2,8 +2,8 @@ -- concatenate a collection of lua modules into one -require "lfs" -require "alt_getopt" +lfs = require "lfs" +alt_getopt = require "alt_getopt" import insert, concat from table import dump, split from require "moonscript.util" From 28849bc8782df355ec70615b67a5716947d387b8 Mon Sep 17 00:00:00 2001 From: Ryan Date: Sun, 25 Sep 2016 12:22:26 -0500 Subject: [PATCH 377/554] moonscript/: remove unneeded variables on stack (#271) --- moonscript/compile/statement.lua | 10 +++++----- moonscript/compile/statement.moon | 10 +++++----- moonscript/compile/value.lua | 6 +++--- moonscript/compile/value.moon | 6 +++--- moonscript/transform/class.lua | 2 +- moonscript/transform/class.moon | 2 +- moonscript/transform/statement.lua | 10 +++++----- moonscript/transform/statement.moon | 10 +++++----- moonscript/transform/value.lua | 4 ++-- moonscript/transform/value.moon | 4 ++-- 10 files changed, 32 insertions(+), 32 deletions(-) diff --git a/moonscript/compile/statement.lua b/moonscript/compile/statement.lua index d2e9dee3..7f1c9063 100644 --- a/moonscript/compile/statement.lua +++ b/moonscript/compile/statement.lua @@ -57,7 +57,7 @@ return { end end, assign = function(self, node) - local _, names, values = unpack(node) + local names, values = unpack(node, 2) local undeclared = self:declare(names) local declare = "local " .. concat(undeclared, ", ") local has_fndef = false @@ -150,7 +150,7 @@ return { end end, ["while"] = function(self, node) - local _, cond, block = unpack(node) + local cond, block = unpack(node, 2) do local _with_0 = self:block(self:line("while ", self:value(cond), " do")) _with_0:stms(block) @@ -158,7 +158,7 @@ return { end end, ["for"] = function(self, node) - local _, name, bounds, block = unpack(node) + local name, bounds, block = unpack(node, 2) local loop = self:line("for ", self:name(name), " = ", self:value({ "explist", unpack(bounds) @@ -173,7 +173,7 @@ return { end end, foreach = function(self, node) - local _, names, exps, block = unpack(node) + local names, exps, block = unpack(node, 2) local loop do local _with_0 = self:line() @@ -210,7 +210,7 @@ return { end end, export = function(self, node) - local _, names = unpack(node) + local names = unpack(node, 2) if type(names) == "string" then if names == "*" then self.export_all = true diff --git a/moonscript/compile/statement.moon b/moonscript/compile/statement.moon index bddd3dca..25f53fd0 100644 --- a/moonscript/compile/statement.moon +++ b/moonscript/compile/statement.moon @@ -26,7 +26,7 @@ import unpack from require "moonscript.util" \append_list [@name name for name in *names], ", " assign: (node) => - _, names, values = unpack node + names, values = unpack node, 2 undeclared = @declare names declare = "local " .. concat(undeclared, ", ") @@ -83,12 +83,12 @@ import unpack from require "moonscript.util" \stms block while: (node) => - _, cond, block = unpack node + cond, block = unpack node, 2 with @block @line "while ", @value(cond), " do" \stms block for: (node) => - _, name, bounds, block = unpack node + name, bounds, block = unpack node, 2 loop = @line "for ", @name(name), " = ", @value({"explist", unpack bounds}), " do" with @block loop \declare {name} @@ -97,7 +97,7 @@ import unpack from require "moonscript.util" -- for x in y ... -- {"foreach", {names...}, {exp...}, body} foreach: (node) => - _, names, exps, block = unpack node + names, exps, block = unpack node, 2 loop = with @line! \append "for " @@ -112,7 +112,7 @@ import unpack from require "moonscript.util" \stms block export: (node) => - _, names = unpack node + names = unpack node, 2 if type(names) == "string" if names == "*" @export_all = true diff --git a/moonscript/compile/value.lua b/moonscript/compile/value.lua index 2c457dc5..ce20dadd 100644 --- a/moonscript/compile/value.lua +++ b/moonscript/compile/value.lua @@ -71,7 +71,7 @@ return { return self:line("(", self:value(node[2]), ")") end, string = function(self, node) - local _, delim, inner = unpack(node) + local delim, inner = unpack(node, 2) local end_delim = delim:gsub("%[", "]") if delim == "'" or delim == '"' then inner = inner:gsub("[\r\n]", string_chars) @@ -133,7 +133,7 @@ return { return self:line(callee_value, actions) end, fndef = function(self, node) - local _, args, whitelist, arrow, block = unpack(node) + local args, whitelist, arrow, block = unpack(node, 2) local default_args = { } local self_args = { } local arg_names @@ -238,7 +238,7 @@ return { end end, table = function(self, node) - local _, items = unpack(node) + local items = unpack(node, 2) do local _with_0 = self:block("{", "}") local format_line diff --git a/moonscript/compile/value.moon b/moonscript/compile/value.moon index 02ae94c8..7cfdda4e 100644 --- a/moonscript/compile/value.moon +++ b/moonscript/compile/value.moon @@ -40,7 +40,7 @@ string_chars = { @line "(", @value(node[2]), ")" string: (node) => - _, delim, inner = unpack node + delim, inner = unpack node, 2 end_delim = delim\gsub "%[", "]" if delim == "'" or delim == '"' inner = inner\gsub "[\r\n]", string_chars @@ -91,7 +91,7 @@ string_chars = { @line callee_value, actions fndef: (node) => - _, args, whitelist, arrow, block = unpack node + args, whitelist, arrow, block = unpack node, 2 default_args = {} self_args = {} @@ -137,7 +137,7 @@ string_chars = { .header = "function("..concat(arg_names, ", ")..")" table: (node) => - _, items = unpack node + items = unpack node, 2 with @block "{", "}" format_line = (tuple) -> if #tuple == 2 diff --git a/moonscript/transform/class.lua b/moonscript/transform/class.lua index f55dce00..74f93c59 100644 --- a/moonscript/transform/class.lua +++ b/moonscript/transform/class.lua @@ -106,7 +106,7 @@ super_scope = function(value, t, key) } end return function(self, node, ret, parent_assign) - local _, name, parent_val, body = unpack(node) + local name, parent_val, body = unpack(node, 2) if parent_val == "" then parent_val = nil end diff --git a/moonscript/transform/class.moon b/moonscript/transform/class.moon index 2a952657..7451375b 100644 --- a/moonscript/transform/class.moon +++ b/moonscript/transform/class.moon @@ -76,7 +76,7 @@ super_scope = (value, t, key) -> } (node, ret, parent_assign) => - _, name, parent_val, body = unpack node + name, parent_val, body = unpack node, 2 parent_val = nil if parent_val == "" parent_cls_name = NameProxy "parent" diff --git a/moonscript/transform/statement.lua b/moonscript/transform/statement.lua index 3e5986f4..6c8a60bf 100644 --- a/moonscript/transform/statement.lua +++ b/moonscript/transform/statement.lua @@ -342,7 +342,7 @@ return Transformer({ end end, update = function(self, node) - local _, name, op, exp = unpack(node) + local name, op, exp = unpack(node, 2) local op_final = op:match("^(.+)=$") if not op_final then error("Unknown op: " .. op) @@ -361,7 +361,7 @@ return Transformer({ }) end, import = function(self, node) - local _, names, source = unpack(node) + local names, source = unpack(node, 2) local table_values do local _accum_0 = { } @@ -402,7 +402,7 @@ return Transformer({ } end, comprehension = function(self, node, action) - local _, exp, clauses = unpack(node) + local exp, clauses = unpack(node, 2) action = action or function(exp) return { exp @@ -492,7 +492,7 @@ return Transformer({ end, ["if"] = function(self, node, ret) if ntype(node[2]) == "assign" then - local _, assign, body = unpack(node) + local assign, body = unpack(node, 2) if destructure.has_destructure(assign[2]) then local name = NameProxy("des") body = { @@ -694,7 +694,7 @@ return Transformer({ node.body = with_continue_listener(node.body) end, switch = function(self, node, ret) - local _, exp, conds = unpack(node) + local exp, conds = unpack(node, 2) local exp_name = NameProxy("exp") local convert_cond convert_cond = function(cond) diff --git a/moonscript/transform/statement.moon b/moonscript/transform/statement.moon index 50de0e0d..2d3a3455 100644 --- a/moonscript/transform/statement.moon +++ b/moonscript/transform/statement.moon @@ -222,14 +222,14 @@ Transformer { nil update: (node) => - _, name, op, exp = unpack node + name, op, exp = unpack node, 2 op_final = op\match "^(.+)=$" error "Unknown op: "..op if not op_final exp = {"parens", exp} unless value_is_singular exp build.assign_one name, {"exp", name, op_final, exp} import: (node) => - _, names, source = unpack node + names, source = unpack node, 2 table_values = for name in *names dest_name = if ntype(name) == "colon" name[2] @@ -242,7 +242,7 @@ Transformer { { "assign", {dest}, {source}, [-1]: node[-1] } comprehension: (node, action) => - _, exp, clauses = unpack node + exp, clauses = unpack node, 2 action = action or (exp) -> {exp} construct_comprehension action(exp), clauses @@ -280,7 +280,7 @@ Transformer { if: (node, ret) => -- expand assign in cond if ntype(node[2]) == "assign" - _, assign, body = unpack node + assign, body = unpack node, 2 if destructure.has_destructure assign[2] name = NameProxy "des" @@ -426,7 +426,7 @@ Transformer { node.body = with_continue_listener node.body switch: (node, ret) => - _, exp, conds = unpack node + exp, conds = unpack node, 2 exp_name = NameProxy "exp" -- convert switch conds into if statment conds diff --git a/moonscript/transform/value.lua b/moonscript/transform/value.lua index 50a49041..33aaef99 100644 --- a/moonscript/transform/value.lua +++ b/moonscript/transform/value.lua @@ -89,7 +89,7 @@ return Transformer({ return a:wrap(node) end, tblcomprehension = function(self, node) - local _, explist, clauses = unpack(node) + local explist, clauses = unpack(node, 2) local key_exp, value_exp = unpack(explist) local accum = NameProxy("tbl") local inner @@ -234,7 +234,7 @@ return Transformer({ end end, block_exp = function(self, node) - local _, body = unpack(node) + local body = unpack(node, 2) local fn = nil local arg_list = { } fn = smart_node(build.fndef({ diff --git a/moonscript/transform/value.moon b/moonscript/transform/value.moon index 18d97a3c..04e16ae2 100644 --- a/moonscript/transform/value.moon +++ b/moonscript/transform/value.moon @@ -56,7 +56,7 @@ Transformer { a\wrap node tblcomprehension: (node) => - _, explist, clauses = unpack node + explist, clauses = unpack node, 2 key_exp, value_exp = unpack explist accum = NameProxy "tbl" @@ -144,7 +144,7 @@ Transformer { } block_exp: (node) => - _, body = unpack node + body = unpack node, 2 fn = nil arg_list = {} From 619db4ba7b52cb7e23e05f5dfac59be899ea487d Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 25 Sep 2016 10:44:09 -0700 Subject: [PATCH 378/554] fixes #265 fixes #264 --- moonscript/cmd/coverage.lua | 1 + moonscript/cmd/coverage.moon | 3 +++ 2 files changed, 4 insertions(+) diff --git a/moonscript/cmd/coverage.lua b/moonscript/cmd/coverage.lua index 4fd36806..bed561f8 100644 --- a/moonscript/cmd/coverage.lua +++ b/moonscript/cmd/coverage.lua @@ -42,6 +42,7 @@ position_to_lines = function(file_content, positions) end local format_file format_file = function(fname, positions) + fname = fname:gsub("^@", "") local file = assert(io.open(fname)) local content = file:read("*a") file:close() diff --git a/moonscript/cmd/coverage.moon b/moonscript/cmd/coverage.moon index dd1d1fa0..281c12aa 100644 --- a/moonscript/cmd/coverage.moon +++ b/moonscript/cmd/coverage.moon @@ -23,6 +23,9 @@ position_to_lines = (file_content, positions) -> lines format_file = (fname, positions) -> + -- sources have @ in front of file names + fname = fname\gsub "^@", "" + file = assert io.open fname content = file\read "*a" file\close! From e0c16a3b6abb405ab613438cfc76f13a5a780865 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 25 Sep 2016 11:25:38 -0700 Subject: [PATCH 379/554] add coverage handler spec --- spec/coverage_output_handler.moon | 51 +++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 spec/coverage_output_handler.moon diff --git a/spec/coverage_output_handler.moon b/spec/coverage_output_handler.moon new file mode 100644 index 00000000..0043e462 --- /dev/null +++ b/spec/coverage_output_handler.moon @@ -0,0 +1,51 @@ + +load_line_table = (chunk_name) -> + import to_lua from require "moonscript.base" + + return unless chunk_name\match "^@" + fname = chunk_name\sub 2 + + file = assert io.open fname + code = file\read "*a" + file\close! + + c, ltable = to_lua code + + return nil, ltable unless c + + line_tables = require "moonscript.line_tables" + line_tables[chunk_name] = ltable + true + +(options) -> + busted = require "busted" + handler = require("busted.outputHandlers.utfTerminal") options + + local spec_name + + coverage = require "moonscript.cmd.coverage" + cov = coverage.CodeCoverage! + + busted.subscribe { "test", "start" }, (context) -> + cov\start! + + busted.subscribe { "test", "end" }, -> + cov\stop! + + busted.subscribe { "suite", "end" }, (context) -> + line_counts = {} + + for chunk_name, counts in pairs cov.line_counts + continue unless chunk_name\match("^@$./") or chunk_name\match "@[^/]" + continue if chunk_name\match "^@spec/" + + if chunk_name\match "%.lua$" + chunk_name = chunk_name\gsub "lua$", "moon" + continue unless load_line_table chunk_name + + line_counts[chunk_name] = counts + + cov.line_counts = line_counts + cov\format_results! + + handler From f2cb2f506c247bced566080cd7a0bfb60c9c3f7b Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 25 Sep 2016 11:28:56 -0700 Subject: [PATCH 380/554] try adding coverage build step --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 11808bda..4e96f64e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,7 @@ env: - LUA=lua5.2 - LUA=lua5.3 - LUA=luajit2.1 # current head of 2.1 branch + - LUA=luajit2.1 BUSTED="-o spec/coverage_output_handler.moon" before_install: - source .travis/setenv_lua.sh @@ -19,4 +20,4 @@ install: - luarocks install loadkit - luarocks make -script: busted +script: busted $BUSTED From 330f5491d688163310e99658b5788067d0ee3e8c Mon Sep 17 00:00:00 2001 From: Kawahara Satoru Date: Mon, 26 Sep 2016 03:36:07 +0900 Subject: [PATCH 381/554] add bitwise update assignment operators (#277) --- moonscript/parse.lua | 2 +- moonscript/parse.moon | 2 +- spec/inputs/syntax.moon | 2 ++ spec/outputs/syntax.lua | 2 ++ 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 2ba504a3..21fecb84 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -146,7 +146,7 @@ local build_grammar = wrap_env(debug_grammar, function(root) 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"), + Update = ((sym("..=") + sym("+=") + sym("-=") + sym("*=") + sym("/=") + sym("%=") + sym("or=") + sym("and=") + sym("&=") + sym("|=") + sym(">>=") + sym("<<=")) / trim) * Exp / mark("update"), CharOperators = Space * C(S("+-*/%^><|&")), WordOperators = op("or") + op("and") + op("<=") + op(">=") + op("~=") + op("!=") + op("==") + op("..") + op("<<") + op(">>") + op("//"), BinaryOperator = (WordOperators + CharOperators) * SpaceBreak ^ 0, diff --git a/moonscript/parse.moon b/moonscript/parse.moon index f7d89268..558d4c82 100644 --- a/moonscript/parse.moon +++ b/moonscript/parse.moon @@ -175,7 +175,7 @@ build_grammar = wrap_env debug_grammar, (root) -> 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" + Update: ((sym"..=" + sym"+=" + sym"-=" + sym"*=" + sym"/=" + sym"%=" + sym"or=" + sym"and=" + sym"&=" + sym"|=" + sym">>=" + sym"<<=") / trim) * Exp / mark"update" CharOperators: Space * C(S"+-*/%^><|&") WordOperators: op"or" + op"and" + op"<=" + op">=" + op"~=" + op"!=" + op"==" + op".." + op"<<" + op">>" + op"//" diff --git a/spec/inputs/syntax.moon b/spec/inputs/syntax.moon index 05ce0671..7b49d04b 100644 --- a/spec/inputs/syntax.moon +++ b/spec/inputs/syntax.moon @@ -243,6 +243,8 @@ another hello, one, a += 3 - 5 a *= 3 + 5 a *= 3 +a >>= 3 +a <<= 3 a /= func "cool" --- diff --git a/spec/outputs/syntax.lua b/spec/outputs/syntax.lua index f19a3e69..bf323195 100644 --- a/spec/outputs/syntax.lua +++ b/spec/outputs/syntax.lua @@ -241,6 +241,8 @@ another(hello, one, two, three, four, { a = a + (3 - 5) a = a * (3 + 5) a = a * 3 +a = a >> 3 +a = a << 3 a = a / func("cool") x["then"] = "hello" x["while"]["true"] = "hello" From 92b269c0cc1e760022b9da9642859498de5f6fa4 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 25 Sep 2016 11:59:08 -0700 Subject: [PATCH 382/554] fixes #286 --- moonscript/parse.lua | 2 +- moonscript/parse.moon | 8 +++++++- spec/inputs/tables.moon | 18 ++++++++++++++++++ spec/outputs/tables.lua | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 58 insertions(+), 2 deletions(-) diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 21fecb84..240041b3 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -183,7 +183,7 @@ local build_grammar = wrap_env(debug_grammar, function(root) ClassBlock = SpaceBreak ^ 1 * Advance * Ct(ClassLine * (SpaceBreak ^ 1 * ClassLine) ^ 0) * PopIndent, ClassLine = CheckIndent * ((KeyValueList / mark("props") + Statement / mark("stm") + Exp / mark("stm")) * sym(",") ^ -1), Export = key("export") * (Cc("class") * ClassDecl + op("*") + op("^") + Ct(NameList) * (sym("=") * Ct(ExpListLow)) ^ -1) / mark("export"), - KeyValue = (sym(":") * -SomeSpace * Name * lpeg.Cp()) / self_assign + Ct((KeyName + sym("[") * Exp * sym("]") + DoubleString + SingleString) * symx(":") * (Exp + TableBlock + SpaceBreak ^ 1 * Exp)), + KeyValue = (sym(":") * -SomeSpace * Name * lpeg.Cp()) / self_assign + Ct((KeyName + sym("[") * Exp * sym("]") + Space * DoubleString + Space * SingleString) * symx(":") * (Exp + TableBlock + SpaceBreak ^ 1 * Exp)), KeyValueList = KeyValue * (sym(",") * KeyValue) ^ 0, KeyValueLine = CheckIndent * KeyValueList * sym(",") ^ -1, FnArgsDef = sym("(") * Ct(FnArgDefList ^ -1) * (key("using") * Ct(NameList + Space * "nil") + Ct("")) * sym(")") + Ct("") * Ct(""), diff --git a/moonscript/parse.moon b/moonscript/parse.moon index 558d4c82..b309de3d 100644 --- a/moonscript/parse.moon +++ b/moonscript/parse.moon @@ -280,7 +280,13 @@ build_grammar = wrap_env debug_grammar, (root) -> op"*" + op"^" + Ct(NameList) * (sym"=" * Ct(ExpListLow))^-1) / mark"export" - KeyValue: (sym":" * -SomeSpace * Name * lpeg.Cp!) / self_assign + Ct((KeyName + sym"[" * Exp * sym"]" + DoubleString + SingleString) * symx":" * (Exp + TableBlock + SpaceBreak^1 * Exp)) + KeyValue: (sym":" * -SomeSpace * Name * lpeg.Cp!) / self_assign + + Ct( + (KeyName + sym"[" * Exp * sym"]" +Space * DoubleString + Space * SingleString) * + symx":" * + (Exp + TableBlock + SpaceBreak^1 * Exp) + ) + KeyValueList: KeyValue * (sym"," * KeyValue)^0 KeyValueLine: CheckIndent * KeyValueList * sym","^-1 diff --git a/spec/inputs/tables.moon b/spec/inputs/tables.moon index 3dad4124..2bf66d70 100644 --- a/spec/inputs/tables.moon +++ b/spec/inputs/tables.moon @@ -140,4 +140,22 @@ thing what: "more" okay: 123 -- a anon table + +-- + +k = { "hello": "world" } +k = { 'hello': 'world' } +k = { "hello": 'world', "hat": "zat" } + +please "hello": "world" +k = "hello": "world", "one": "zone" + +f = "one", "two": three, "four" +f = "two": three, "four" +f = { "one", "two": three, "four" } + + +j = "one", "two": three, "four": five, 6, 7 + + nil diff --git a/spec/outputs/tables.lua b/spec/outputs/tables.lua index 0cad58a5..b6a4f587 100644 --- a/spec/outputs/tables.lua +++ b/spec/outputs/tables.lua @@ -171,4 +171,36 @@ thing({ local _ = { okay = 123 } +local k = { + ["hello"] = "world" +} +k = { + ['hello'] = 'world' +} +k = { + ["hello"] = 'world', + ["hat"] = "zat" +} +please({ + ["hello"] = "world" +}) +k = { + ["hello"] = "world", + ["one"] = "zone" +} +local f = "one", { + ["two"] = three +}, "four" +f = { + ["two"] = three +}, "four" +f = { + "one", + ["two"] = three, + "four" +} +local j = "one", { + ["two"] = three, + ["four"] = five +}, 6, 7 return nil \ No newline at end of file From bf437b2cd242a882a200f10cc9b93192ebba0088 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 25 Sep 2016 12:08:10 -0700 Subject: [PATCH 383/554] class names aren't refs, fixes #287 --- moonscript/transform/statement.lua | 8 +++- moonscript/transform/statement.moon | 7 ++- spec/inputs/local.moon | 11 +++++ spec/outputs/local.lua | 67 +++++++++++++++++++++++++++++ 4 files changed, 91 insertions(+), 2 deletions(-) diff --git a/moonscript/transform/statement.lua b/moonscript/transform/statement.lua index 6c8a60bf..47dd0de7 100644 --- a/moonscript/transform/statement.lua +++ b/moonscript/transform/statement.lua @@ -204,7 +204,13 @@ return Transformer({ local _continue_0 = false repeat local name = names[_index_0] - if not (name[2]:match("^%u")) then + local str_name + if ntype(name) == "ref" then + str_name = name[2] + else + str_name = name + end + if not (str_name:match("^%u")) then _continue_0 = true break end diff --git a/moonscript/transform/statement.moon b/moonscript/transform/statement.moon index 2d3a3455..42c3ec79 100644 --- a/moonscript/transform/statement.moon +++ b/moonscript/transform/statement.moon @@ -122,7 +122,12 @@ Transformer { if node[2] == "^" names = for name in *names - continue unless name[2]\match "^%u" + str_name = if ntype(name) == "ref" + name[2] + else + name + + continue unless str_name\match "^%u" name {"declare", names} diff --git a/spec/inputs/local.moon b/spec/inputs/local.moon index d4a616ca..fec78b18 100644 --- a/spec/inputs/local.moon +++ b/spec/inputs/local.moon @@ -75,6 +75,17 @@ do d = 2323 +do + local ^ + lowercase = 5 + Uppercase = 3 + + class One + Five = 6 + + class Two + class No + do local * -- this generates a nil value in the body diff --git a/spec/outputs/local.lua b/spec/outputs/local.lua index db19697a..3ee8623e 100644 --- a/spec/outputs/local.lua +++ b/spec/outputs/local.lua @@ -70,6 +70,73 @@ do d = 200 d = 2323 end +do + local Uppercase, One, Two + local lowercase = 5 + Uppercase = 3 + do + local _class_0 + local Five + local _base_0 = { } + _base_0.__index = _base_0 + _class_0 = setmetatable({ + __init = function() end, + __base = _base_0, + __name = "One" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + Five = 6 + One = _class_0 + end + do + local _class_0 + local No + local _base_0 = { } + _base_0.__index = _base_0 + _class_0 = setmetatable({ + __init = function() end, + __base = _base_0, + __name = "Two" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + do + local _class_1 + local _base_1 = { } + _base_1.__index = _base_1 + _class_1 = setmetatable({ + __init = function() end, + __base = _base_1, + __name = "No" + }, { + __index = _base_1, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_1) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_1.__class = _class_1 + No = _class_1 + end + Two = _class_0 + end +end do local _list_0 = { } for _index_0 = 1, #_list_0 do From f2363f53cdcd917a4d16ba74fe426cd09929e400 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 25 Sep 2016 12:53:05 -0700 Subject: [PATCH 384/554] show_line_position --- moonscript/parse/util.lua | 63 ++++++++++++++++++++++++++++++++++++-- moonscript/parse/util.moon | 46 ++++++++++++++++++++++++++-- 2 files changed, 103 insertions(+), 6 deletions(-) diff --git a/moonscript/parse/util.lua b/moonscript/parse/util.lua index e9d4554b..2687384b 100644 --- a/moonscript/parse/util.lua +++ b/moonscript/parse/util.lua @@ -41,6 +41,58 @@ extract_line = function(str, start_pos) end return str:match("^.-$") end +local show_line_position +show_line_position = function(str, pos, context) + if context == nil then + context = true + end + local lines = { + { } + } + for c in str:gmatch(".") do + lines[#lines] = lines[#lines] or { } + table.insert(lines[#lines], c) + if c == "\n" then + lines[#lines + 1] = { } + end + end + for i, line in ipairs(lines) do + lines[i] = table.concat(line) + end + local out + local remaining = pos - 1 + for k, line in ipairs(lines) do + if remaining < #line then + local left = line:sub(1, remaining) + local right = line:sub(remaining + 1) + out = { + tostring(left) .. "◉" .. tostring(right) + } + if context then + do + local before = lines[k - 1] + if before then + table.insert(out, 1, before) + end + end + do + local after = lines[k + 1] + if after then + table.insert(out, after) + end + end + end + break + else + remaining = remaining - #line + end + end + if not (out) then + return "-" + end + out = table.concat(out) + return (out:gsub("\n*$", "")) +end local mark mark = function(name) return function(...) @@ -60,9 +112,12 @@ pos = function(patt) end end local got -got = function(what) +got = function(what, context) + if context == nil then + context = true + end return Cmt("", function(str, pos) - print("++ got " .. tostring(what), "[" .. tostring(extract_line(str, pos)) .. "]") + print("++ got " .. tostring(what), "[" .. tostring(show_line_position(str, pos, context)) .. "]") return true end) end @@ -245,5 +300,7 @@ return { join_chain = join_chain, wrap_decorator = wrap_decorator, check_lua_string = check_lua_string, - self_assign = self_assign + self_assign = self_assign, + got = got, + show_line_position = show_line_position } diff --git a/moonscript/parse/util.moon b/moonscript/parse/util.moon index af33279e..17adf77a 100644 --- a/moonscript/parse/util.moon +++ b/moonscript/parse/util.moon @@ -31,6 +31,46 @@ extract_line = (str, start_pos) -> str\match "^.-$" +-- print the line with a token showing the position +show_line_position = (str, pos, context=true) -> + lines = { {} } + for c in str\gmatch "." + lines[#lines] or= {} + table.insert lines[#lines], c + if c == "\n" + lines[#lines + 1] = {} + + for i, line in ipairs lines + lines[i] = table.concat line + + local out + + remaining = pos - 1 + for k, line in ipairs lines + if remaining < #line + left = line\sub 1, remaining + right = line\sub remaining + 1 + out = { + "#{left}◉#{right}" + } + + if context + if before = lines[k - 1] + table.insert out, 1, before + + if after = lines[k + 1] + table.insert out, after + + break + else + remaining -= #line + + + return "-" unless out + + out = table.concat out + (out\gsub "\n*$", "") + -- used to identify a capture with a label mark = (name) -> (...) -> {name, ...} @@ -46,9 +86,9 @@ pos = (patt) -> -- generates a debug pattern that always succeeds and prints out where we are -- in the buffer with a label -got = (what) -> +got = (what, context=true) -> Cmt "", (str, pos) -> - print "++ got #{what}", "[#{extract_line str, pos}]" + print "++ got #{what}", "[#{show_line_position str, pos, context}]" true -- converts 1 element array to its value, otherwise marks it @@ -154,4 +194,4 @@ self_assign = (name, pos) -> { :Indent, :Cut, :ensure, :extract_line, :mark, :pos, :flatten_or_mark, :is_assignable, :check_assignable, :format_assign, :format_single_assign, :sym, :symx, :simple_string, :wrap_func_arg, :join_chain, :wrap_decorator, - :check_lua_string, :self_assign } + :check_lua_string, :self_assign, :got, :show_line_position } From 2f1dd92012afd89ce22e0babf774749a4d77d245 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 25 Sep 2016 12:57:54 -0700 Subject: [PATCH 385/554] fix empty line consumption for else, fixes #276 --- moonscript/parse.lua | 8 ++++---- moonscript/parse.moon | 7 ++++--- spec/inputs/cond.moon | 26 ++++++++++++++++++++++++++ spec/outputs/cond.lua | 19 ++++++++++++++++++- 4 files changed, 52 insertions(+), 8 deletions(-) diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 240041b3..10643a2b 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -27,10 +27,10 @@ Num = Space * (Num / function(v) v } end) -local Indent, Cut, ensure, extract_line, mark, pos, flatten_or_mark, is_assignable, check_assignable, format_assign, format_single_assign, sym, symx, simple_string, wrap_func_arg, join_chain, wrap_decorator, check_lua_string, self_assign +local Indent, Cut, ensure, extract_line, mark, pos, flatten_or_mark, is_assignable, check_assignable, format_assign, format_single_assign, sym, symx, simple_string, wrap_func_arg, join_chain, wrap_decorator, check_lua_string, self_assign, got do local _obj_0 = require("moonscript.parse.util") - Indent, Cut, ensure, extract_line, mark, pos, flatten_or_mark, is_assignable, check_assignable, format_assign, format_single_assign, sym, symx, simple_string, wrap_func_arg, join_chain, wrap_decorator, check_lua_string, self_assign = _obj_0.Indent, _obj_0.Cut, _obj_0.ensure, _obj_0.extract_line, _obj_0.mark, _obj_0.pos, _obj_0.flatten_or_mark, _obj_0.is_assignable, _obj_0.check_assignable, _obj_0.format_assign, _obj_0.format_single_assign, _obj_0.sym, _obj_0.symx, _obj_0.simple_string, _obj_0.wrap_func_arg, _obj_0.join_chain, _obj_0.wrap_decorator, _obj_0.check_lua_string, _obj_0.self_assign + Indent, Cut, ensure, extract_line, mark, pos, flatten_or_mark, is_assignable, check_assignable, format_assign, format_single_assign, sym, symx, simple_string, wrap_func_arg, join_chain, wrap_decorator, check_lua_string, self_assign, got = _obj_0.Indent, _obj_0.Cut, _obj_0.ensure, _obj_0.extract_line, _obj_0.mark, _obj_0.pos, _obj_0.flatten_or_mark, _obj_0.is_assignable, _obj_0.check_assignable, _obj_0.format_assign, _obj_0.format_single_assign, _obj_0.sym, _obj_0.symx, _obj_0.simple_string, _obj_0.wrap_func_arg, _obj_0.join_chain, _obj_0.wrap_decorator, _obj_0.check_lua_string, _obj_0.self_assign, _obj_0.got end local build_grammar = wrap_env(debug_grammar, function(root) local _indent = Stack(0) @@ -131,8 +131,8 @@ local build_grammar = wrap_env(debug_grammar, function(root) SwitchCase = key("when") * Ct(ExpList) * key("then") ^ -1 * Body / mark("case"), SwitchElse = key("else") * Body / mark("else"), IfCond = Exp * Assign ^ -1 / format_single_assign, - IfElse = (Break * CheckIndent) ^ -1 * EmptyLine ^ 0 * key("else") * Body / mark("else"), - IfElseIf = (Break * CheckIndent) ^ -1 * EmptyLine ^ 0 * key("elseif") * pos(IfCond) * key("then") ^ -1 * Body / mark("elseif"), + IfElse = (Break * EmptyLine ^ 0 * CheckIndent) ^ -1 * key("else") * Body / mark("else"), + IfElseIf = (Break * EmptyLine ^ 0 * CheckIndent) ^ -1 * key("elseif") * pos(IfCond) * key("then") ^ -1 * Body / mark("elseif"), If = key("if") * IfCond * key("then") ^ -1 * Body * IfElseIf ^ 0 * IfElse ^ -1 / mark("if"), Unless = key("unless") * IfCond * key("then") ^ -1 * Body * IfElseIf ^ 0 * IfElse ^ -1 / mark("unless"), While = key("while") * DisableDo * ensure(Exp, PopDo) * key("do") ^ -1 * Body / mark("while"), diff --git a/moonscript/parse.moon b/moonscript/parse.moon index b309de3d..6daf9eec 100644 --- a/moonscript/parse.moon +++ b/moonscript/parse.moon @@ -27,7 +27,8 @@ Num = Space * (Num / (v) -> {"number", v}) :Indent, :Cut, :ensure, :extract_line, :mark, :pos, :flatten_or_mark, :is_assignable, :check_assignable, :format_assign, :format_single_assign, :sym, :symx, :simple_string, :wrap_func_arg, :join_chain, - :wrap_decorator, :check_lua_string, :self_assign + :wrap_decorator, :check_lua_string, :self_assign, :got + } = require "moonscript.parse.util" @@ -150,8 +151,8 @@ build_grammar = wrap_env debug_grammar, (root) -> IfCond: Exp * Assign^-1 / format_single_assign - IfElse: (Break * CheckIndent)^-1 * EmptyLine^0 * key"else" * Body / mark"else" - IfElseIf: (Break * CheckIndent)^-1 * EmptyLine^0 * key"elseif" * pos(IfCond) * key"then"^-1 * Body / mark"elseif" + IfElse: (Break * EmptyLine^0 * CheckIndent)^-1 * key"else" * Body / mark"else" + IfElseIf: (Break * EmptyLine^0 * CheckIndent)^-1 * key"elseif" * pos(IfCond) * key"then"^-1 * Body / mark"elseif" If: key"if" * IfCond * key"then"^-1 * Body * IfElseIf^0 * IfElse^-1 / mark"if" Unless: key"unless" * IfCond * key"then"^-1 * Body * IfElseIf^0 * IfElse^-1 / mark"unless" diff --git a/spec/inputs/cond.moon b/spec/inputs/cond.moon index 89097216..3bf966fb 100644 --- a/spec/inputs/cond.moon +++ b/spec/inputs/cond.moon @@ -154,3 +154,29 @@ a,c,b = "cool" if something +--- + +j = if 1 + if 2 + 3 +else 6 + + +m = if 1 + + + + if 2 + + + 3 + + +else 6 + + + +nil + + + diff --git a/spec/outputs/cond.lua b/spec/outputs/cond.lua index 036f5469..30e87626 100644 --- a/spec/outputs/cond.lua +++ b/spec/outputs/cond.lua @@ -250,4 +250,21 @@ local a = 12 local c, b if something then a, c, b = "cool" -end \ No newline at end of file +end +local j +if 1 then + if 2 then + j = 3 + end +else + j = 6 +end +local m +if 1 then + if 2 then + m = 3 + end +else + m = 6 +end +return nil \ No newline at end of file From dfc4f7b0167274c8ed0e11e2ac8ec03e6052487b Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 25 Sep 2016 13:11:39 -0700 Subject: [PATCH 386/554] add note in readme about windows builds --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index b282f75d..fb79f111 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,15 @@ busted Writing specs is a bit more complicated. Check out [the spec writing guide](spec/README.md). +## Binaries + +Precompiled versions of MoonScript are provided for Windows. You can find them +in the [GitHub releases page](https://github.com/leafo/moonscript/releases). +(Scroll down to the `win32-` tags. + +The build code can be found in the [`binaries` +branch](https://github.com/leafo/moonscript/tree/binaries) + ## Editor Support * [Vim](https://github.com/leafo/moonscript-vim) From c19a7fd2c32c225d411f460f20420681cab2f9f2 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 25 Sep 2016 14:07:35 -0700 Subject: [PATCH 387/554] allow assignment in `unless` block, fixes #251 --- moonscript/transform/statement.lua | 36 +++++++++++++++++++++-------- moonscript/transform/statement.moon | 16 +++++++++++-- spec/inputs/cond.moon | 8 +++++++ spec/outputs/cond.lua | 9 ++++++++ 4 files changed, 58 insertions(+), 11 deletions(-) diff --git a/moonscript/transform/statement.lua b/moonscript/transform/statement.lua index 47dd0de7..7303666a 100644 --- a/moonscript/transform/statement.lua +++ b/moonscript/transform/statement.lua @@ -484,17 +484,35 @@ return Transformer({ return wrapped end, unless = function(self, node) - return { - "if", - { - "not", + local clause = node[2] + if ntype(clause) == "assign" then + if destructure.has_destructure(clause[2]) then + error("destructure not allowed in unless assignment") + end + return build["do"]({ + clause, { - "parens", - node[2] + "if", + { + "not", + clause[2][1] + }, + unpack(node, 3) } - }, - unpack(node, 3) - } + }) + else + return { + "if", + { + "not", + { + "parens", + clause + } + }, + unpack(node, 3) + } + end end, ["if"] = function(self, node, ret) if ntype(node[2]) == "assign" then diff --git a/moonscript/transform/statement.moon b/moonscript/transform/statement.moon index 42c3ec79..f5cf3a54 100644 --- a/moonscript/transform/statement.moon +++ b/moonscript/transform/statement.moon @@ -280,7 +280,19 @@ Transformer { wrapped unless: (node) => - { "if", {"not", {"parens", node[2]}}, unpack node, 3 } + clause = node[2] + + if ntype(clause) == "assign" + if destructure.has_destructure clause[2] + error "destructure not allowed in unless assignment" + + build.do { + clause + { "if", {"not", clause[2][1]}, unpack node, 3 } + } + + else + { "if", {"not", {"parens", clause}}, unpack node, 3 } if: (node, ret) => -- expand assign in cond @@ -300,7 +312,7 @@ Transformer { } else name = assign[2][1] - return build["do"] { + return build.do { assign {"if", name, unpack node, 3} } diff --git a/spec/inputs/cond.moon b/spec/inputs/cond.moon index 3bf966fb..18e42b91 100644 --- a/spec/inputs/cond.moon +++ b/spec/inputs/cond.moon @@ -147,6 +147,14 @@ print "hello" unless value dddd = {1,2,3} unless value + +-- + +do + j = 100 + unless j = hi! + error "not j!" + ---------------- a = 12 diff --git a/spec/outputs/cond.lua b/spec/outputs/cond.lua index 30e87626..35e7ac56 100644 --- a/spec/outputs/cond.lua +++ b/spec/outputs/cond.lua @@ -246,6 +246,15 @@ if not (value) then 3 } end +do + local j = 100 + do + j = hi() + if not j then + error("not j!") + end + end +end local a = 12 local c, b if something then From c024c83975c369b60be3f3070c33edc2409e8240 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 25 Sep 2016 14:07:41 -0700 Subject: [PATCH 388/554] spec indentation --- spec/inputs/unless_else.moon | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/inputs/unless_else.moon b/spec/inputs/unless_else.moon index b421d4d0..fe96c0bd 100644 --- a/spec/inputs/unless_else.moon +++ b/spec/inputs/unless_else.moon @@ -1,5 +1,5 @@ if a - unless b - print "hi" - elseif c - print "not hi" + unless b + print "hi" + elseif c + print "not hi" From e0da63c50107584fd8255d13ffce5b08fb5a0f26 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 25 Sep 2016 14:20:57 -0700 Subject: [PATCH 389/554] assignable name list in comprehension/decorator for in loop, fixes #236 --- moonscript/parse.lua | 2 +- moonscript/parse.moon | 2 +- spec/inputs/comprehension.moon | 13 ++++++ spec/outputs/comprehension.lua | 79 ++++++++++++++++++++++++++++++++++ 4 files changed, 94 insertions(+), 2 deletions(-) diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 10643a2b..be2c1529 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -142,7 +142,7 @@ local build_grammar = wrap_env(debug_grammar, function(root) Comprehension = sym("[") * Exp * CompInner * sym("]") / mark("comprehension"), TblComprehension = sym("{") * Ct(Exp * (sym(",") * Exp) ^ -1) * CompInner * sym("}") / mark("tblcomprehension"), CompInner = Ct((CompForEach + CompFor) * CompClause ^ 0), - CompForEach = key("for") * Ct(NameList) * key("in") * (sym("*") * Exp / mark("unpack") + Exp) / mark("foreach"), + CompForEach = key("for") * Ct(AssignableNameList) * 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"), diff --git a/moonscript/parse.moon b/moonscript/parse.moon index 6daf9eec..708f7c91 100644 --- a/moonscript/parse.moon +++ b/moonscript/parse.moon @@ -171,7 +171,7 @@ build_grammar = wrap_env debug_grammar, (root) -> TblComprehension: sym"{" * Ct(Exp * (sym"," * Exp)^-1) * CompInner * sym"}" / mark"tblcomprehension" CompInner: Ct((CompForEach + CompFor) * CompClause^0) - CompForEach: key"for" * Ct(NameList) * key"in" * (sym"*" * Exp / mark"unpack" + Exp) / mark"foreach" + CompForEach: key"for" * Ct(AssignableNameList) * 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" diff --git a/spec/inputs/comprehension.moon b/spec/inputs/comprehension.moon index 345d5b70..51b39857 100644 --- a/spec/inputs/comprehension.moon +++ b/spec/inputs/comprehension.moon @@ -30,4 +30,17 @@ dd = [y for i=1,10 when cool for thing in y when x > 3 when c + 3] {"hello", "world" for i=1,10} +-- + +j = [a for {a,b,c} in things] +k = [a for {a,b,c} in *things] +i = [hello for {:hello, :world} in *things] + +hj = {a,c for {a,b,c} in things} +hk = {a,c for {a,b,c} in *things} +hi = {hello,world for {:hello, :world} in *things} + +ok(a,b,c) for {a,b,c} in things + + nil diff --git a/spec/outputs/comprehension.lua b/spec/outputs/comprehension.lua index ec3569a1..c53290ea 100644 --- a/spec/outputs/comprehension.lua +++ b/spec/outputs/comprehension.lua @@ -168,4 +168,83 @@ do end _ = _tbl_0 end +local j +do + local _accum_0 = { } + local _len_0 = 1 + for _des_0 in things do + local a, b, c + a, b, c = _des_0[1], _des_0[2], _des_0[3] + _accum_0[_len_0] = a + _len_0 = _len_0 + 1 + end + j = _accum_0 +end +local k +do + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = things + for _index_0 = 1, #_list_0 do + local _des_0 = _list_0[_index_0] + local a, b, c + a, b, c = _des_0[1], _des_0[2], _des_0[3] + _accum_0[_len_0] = a + _len_0 = _len_0 + 1 + end + k = _accum_0 +end +local i +do + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = things + for _index_0 = 1, #_list_0 do + local _des_0 = _list_0[_index_0] + local hello, world + hello, world = _des_0.hello, _des_0.world + _accum_0[_len_0] = hello + _len_0 = _len_0 + 1 + end + i = _accum_0 +end +local hj +do + local _tbl_0 = { } + for _des_0 in things do + local a, b, c + a, b, c = _des_0[1], _des_0[2], _des_0[3] + _tbl_0[a] = c + end + hj = _tbl_0 +end +local hk +do + local _tbl_0 = { } + local _list_0 = things + for _index_0 = 1, #_list_0 do + local _des_0 = _list_0[_index_0] + local a, b, c + a, b, c = _des_0[1], _des_0[2], _des_0[3] + _tbl_0[a] = c + end + hk = _tbl_0 +end +local hi +do + local _tbl_0 = { } + local _list_0 = things + for _index_0 = 1, #_list_0 do + local _des_0 = _list_0[_index_0] + local hello, world + hello, world = _des_0.hello, _des_0.world + _tbl_0[hello] = world + end + hi = _tbl_0 +end +for _des_0 in things do + local a, b, c + a, b, c = _des_0[1], _des_0[2], _des_0[3] + ok(a, b, c) +end return nil \ No newline at end of file From d8830b17f3dafcdd6b0357d584bd296730ce5ea6 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 25 Sep 2016 14:33:55 -0700 Subject: [PATCH 390/554] allow whitespace around function arguments when in parens, fixes #274 --- moonscript/parse.lua | 3 ++- moonscript/parse.moon | 3 ++- spec/inputs/whitespace.moon | 19 +++++++++++++++++++ spec/outputs/whitespace.lua | 8 ++++++-- 4 files changed, 29 insertions(+), 4 deletions(-) diff --git a/moonscript/parse.lua b/moonscript/parse.lua index be2c1529..16d94313 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -164,7 +164,8 @@ local build_grammar = wrap_env(debug_grammar, function(root) LuaStringClose = "]" * P("=") ^ 0 * "]", Callable = pos(Name / mark("ref")) + SelfName + VarArg + Parens / mark("parens"), Parens = sym("(") * SpaceBreak ^ 0 * Exp * SpaceBreak ^ 0 * sym(")"), - FnArgs = symx("(") * SpaceBreak ^ 0 * Ct(ExpList ^ -1) * SpaceBreak ^ 0 * sym(")") + sym("!") * -P("=") * Ct(""), + FnArgs = symx("(") * SpaceBreak ^ 0 * Ct(FnArgsExpList ^ -1) * SpaceBreak ^ 0 * sym(")") + sym("!") * -P("=") * Ct(""), + FnArgsExpList = Exp * (sym(",") * White * Exp) ^ 0, Chain = (Callable + String + -S(".\\")) * ChainItems / mark("chain") + Space * (DotChainItem * ChainItems ^ -1 + ColonChain) / mark("chain"), ChainItems = ChainItem ^ 1 * ColonChain ^ -1 + ColonChain, ChainItem = Invoke + DotChainItem + Slice + symx("[") * Exp / mark("index") * sym("]"), diff --git a/moonscript/parse.moon b/moonscript/parse.moon index 708f7c91..baef3d08 100644 --- a/moonscript/parse.moon +++ b/moonscript/parse.moon @@ -227,7 +227,8 @@ build_grammar = wrap_env debug_grammar, (root) -> Callable: pos(Name / mark"ref") + SelfName + VarArg + Parens / mark"parens" Parens: sym"(" * SpaceBreak^0 * Exp * SpaceBreak^0 * sym")" - FnArgs: symx"(" * SpaceBreak^0 * Ct(ExpList^-1) * SpaceBreak^0 * sym")" + sym"!" * -P"=" * Ct"" + FnArgs: symx"(" * SpaceBreak^0 * Ct(FnArgsExpList^-1) * SpaceBreak^0 * sym")" + sym"!" * -P"=" * Ct"" + FnArgsExpList: Exp * (sym"," * White * Exp)^0 Chain: (Callable + String + -S".\\") * ChainItems / mark"chain" + Space * (DotChainItem * ChainItems^-1 + ColonChain) / mark"chain" diff --git a/spec/inputs/whitespace.moon b/spec/inputs/whitespace.moon index a8242228..4a2ff1fa 100644 --- a/spec/inputs/whitespace.moon +++ b/spec/inputs/whitespace.moon @@ -81,3 +81,22 @@ if hello 1,2,3, print "hello" +-- + +a( + one, two, three +) + +b( + one, + two, + three +) + + +c(one, two, + three, four) + +-- + +nil diff --git a/spec/outputs/whitespace.lua b/spec/outputs/whitespace.lua index ce2d7920..c112a055 100644 --- a/spec/outputs/whitespace.lua +++ b/spec/outputs/whitespace.lua @@ -72,5 +72,9 @@ if hello(1, 2, 3, world, world) then print("hello") end if hello(1, 2, 3, world, world) then - return print("hello") -end \ No newline at end of file + print("hello") +end +a(one, two, three) +b(one, two, three) +c(one, two, three, four) +return nil \ No newline at end of file From 0a2399ef396aab822ad942eda2ea6da00eba5c8d Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 25 Sep 2016 15:53:40 -0700 Subject: [PATCH 391/554] let newlines break arguments in fn call with parens --- moonscript/parse.lua | 2 +- moonscript/parse.moon | 2 +- spec/inputs/funcs.moon | 38 ++++++++++++++++++++++++++++++++++++++ spec/outputs/funcs.lua | 17 +++++++++++++++-- 4 files changed, 55 insertions(+), 4 deletions(-) diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 16d94313..3b9b832b 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -165,7 +165,7 @@ local build_grammar = wrap_env(debug_grammar, function(root) Callable = pos(Name / mark("ref")) + SelfName + VarArg + Parens / mark("parens"), Parens = sym("(") * SpaceBreak ^ 0 * Exp * SpaceBreak ^ 0 * sym(")"), FnArgs = symx("(") * SpaceBreak ^ 0 * Ct(FnArgsExpList ^ -1) * SpaceBreak ^ 0 * sym(")") + sym("!") * -P("=") * Ct(""), - FnArgsExpList = Exp * (sym(",") * White * Exp) ^ 0, + FnArgsExpList = Exp * ((Break + sym(",")) * White * Exp) ^ 0, Chain = (Callable + String + -S(".\\")) * ChainItems / mark("chain") + Space * (DotChainItem * ChainItems ^ -1 + ColonChain) / mark("chain"), ChainItems = ChainItem ^ 1 * ColonChain ^ -1 + ColonChain, ChainItem = Invoke + DotChainItem + Slice + symx("[") * Exp / mark("index") * sym("]"), diff --git a/moonscript/parse.moon b/moonscript/parse.moon index baef3d08..5ffc1f0d 100644 --- a/moonscript/parse.moon +++ b/moonscript/parse.moon @@ -228,7 +228,7 @@ build_grammar = wrap_env debug_grammar, (root) -> Parens: sym"(" * SpaceBreak^0 * Exp * SpaceBreak^0 * sym")" FnArgs: symx"(" * SpaceBreak^0 * Ct(FnArgsExpList^-1) * SpaceBreak^0 * sym")" + sym"!" * -P"=" * Ct"" - FnArgsExpList: Exp * (sym"," * White * Exp)^0 + FnArgsExpList: Exp * ((Break + sym",") * White * Exp)^0 Chain: (Callable + String + -S".\\") * ChainItems / mark"chain" + Space * (DotChainItem * ChainItems^-1 + ColonChain) / mark"chain" diff --git a/spec/inputs/funcs.moon b/spec/inputs/funcs.moon index 8c17439b..a6812255 100644 --- a/spec/inputs/funcs.moon +++ b/spec/inputs/funcs.moon @@ -59,3 +59,41 @@ k -> if yes then return else return -> real_name if something +-- + +d( + -> + print "hello world" + 10 +) + + + +d( + 1,2,3 + 4 + 5 + 6 + + if something + print "okay" + 10 + + 10,20 +) + + +f( + + )( + + )( + what + )(-> + print "srue" + 123) + +-- + + +nil diff --git a/spec/outputs/funcs.lua b/spec/outputs/funcs.lua index 35dee928..02f4f756 100644 --- a/spec/outputs/funcs.lua +++ b/spec/outputs/funcs.lua @@ -108,8 +108,21 @@ k(function() return end end) -return function() +_ = function() if something then return real_name end -end \ No newline at end of file +end +d(function() + return print("hello world") +end, 10) +d(1, 2, 3, 4, 5, 6, (function() + if something then + print("okay") + return 10 + end +end)(), 10, 20) +f()()(what)(function() + return print("srue") +end, 123) +return nil \ No newline at end of file From 2e7d5153f193ca19e7de9941ae09a1ad7bf00962 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 25 Sep 2016 17:34:59 -0700 Subject: [PATCH 392/554] expression can be used inside slide boundaries, fixes #233 --- moonscript/parse.lua | 2 +- moonscript/parse.moon | 2 +- spec/inputs/comprehension.moon | 6 ++++++ spec/outputs/comprehension.lua | 10 ++++++++++ 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 3b9b832b..0ed7e4e5 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -155,7 +155,7 @@ local build_grammar = wrap_env(debug_grammar, function(root) SimpleValue = If + Unless + Switch + With + ClassDecl + ForEach + For + While + Cmt(Do, check_do) + sym("-") * -SomeSpace * Exp / mark("minus") + sym("#") * Exp / mark("length") + sym("~") * Exp / mark("bitnot") + key("not") * Exp / mark("not") + TblComprehension + TableLit + Comprehension + FunLit + Num, ChainValue = (Chain + Callable) * Ct(InvokeArgs ^ -1) / join_chain, Value = pos(SimpleValue + Ct(KeyValueList) / mark("table") + ChainValue + String), - SliceValue = SimpleValue + ChainValue, + SliceValue = Exp, String = Space * DoubleString + Space * SingleString + LuaString, SingleString = simple_string("'"), DoubleString = simple_string('"', true), diff --git a/moonscript/parse.moon b/moonscript/parse.moon index 5ffc1f0d..0403f333 100644 --- a/moonscript/parse.moon +++ b/moonscript/parse.moon @@ -211,7 +211,7 @@ build_grammar = wrap_env debug_grammar, (root) -> ChainValue + String) - SliceValue: SimpleValue + ChainValue + SliceValue: Exp String: Space * DoubleString + Space * SingleString + LuaString SingleString: simple_string("'") diff --git a/spec/inputs/comprehension.moon b/spec/inputs/comprehension.moon index 51b39857..1609d79e 100644 --- a/spec/inputs/comprehension.moon +++ b/spec/inputs/comprehension.moon @@ -42,5 +42,11 @@ hi = {hello,world for {:hello, :world} in *things} ok(a,b,c) for {a,b,c} in things +-- + +[item for item in *items[1 + 2,3+4]] +[item for item in *items[hello! * 4, 2 - thing[4]]] + + nil diff --git a/spec/outputs/comprehension.lua b/spec/outputs/comprehension.lua index c53290ea..15a93890 100644 --- a/spec/outputs/comprehension.lua +++ b/spec/outputs/comprehension.lua @@ -247,4 +247,14 @@ for _des_0 in things do a, b, c = _des_0[1], _des_0[2], _des_0[3] ok(a, b, c) end +local _max_0 = 3 + 4 +for _index_0 = 1 + 2, _max_0 < 0 and #items + _max_0 or _max_0 do + local item = items[_index_0] + _ = item +end +local _max_1 = 2 - thing[4] +for _index_0 = hello() * 4, _max_1 < 0 and #items + _max_1 or _max_1 do + local item = items[_index_0] + _ = item +end return nil \ No newline at end of file From 5d074c9e62442081b8c3edb57e23470ed892eed3 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 25 Sep 2016 17:45:50 -0700 Subject: [PATCH 393/554] allow whitespace around function argument declaration, fixes #227 --- moonscript/parse.lua | 4 ++-- moonscript/parse.moon | 6 +++--- spec/inputs/funcs.moon | 21 +++++++++++++++++++++ spec/outputs/funcs.lua | 33 +++++++++++++++++++++++++++++++++ 4 files changed, 59 insertions(+), 5 deletions(-) diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 0ed7e4e5..f3fda489 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -187,8 +187,8 @@ local build_grammar = wrap_env(debug_grammar, function(root) KeyValue = (sym(":") * -SomeSpace * Name * lpeg.Cp()) / self_assign + Ct((KeyName + sym("[") * Exp * sym("]") + Space * DoubleString + Space * SingleString) * symx(":") * (Exp + TableBlock + SpaceBreak ^ 1 * Exp)), KeyValueList = KeyValue * (sym(",") * KeyValue) ^ 0, KeyValueLine = CheckIndent * KeyValueList * sym(",") ^ -1, - FnArgsDef = sym("(") * Ct(FnArgDefList ^ -1) * (key("using") * Ct(NameList + Space * "nil") + Ct("")) * sym(")") + Ct("") * Ct(""), - FnArgDefList = FnArgDef * (sym(",") * FnArgDef) ^ 0 * (sym(",") * Ct(VarArg)) ^ 0 + Ct(VarArg), + FnArgsDef = sym("(") * White * Ct(FnArgDefList ^ -1) * (key("using") * Ct(NameList + Space * "nil") + Ct("")) * White * sym(")") + Ct("") * Ct(""), + FnArgDefList = FnArgDef * (sym(",") * White * FnArgDef) ^ 0 * (sym(",") * White * Ct(VarArg)) ^ 0 + Ct(VarArg), FnArgDef = Ct((Name + SelfName) * (sym("=") * Exp) ^ -1), FunLit = FnArgsDef * (sym("->") * Cc("slim") + sym("=>") * Cc("fat")) * (Body + Ct("")) / mark("fndef"), NameList = Name * (sym(",") * Name) ^ 0, diff --git a/moonscript/parse.moon b/moonscript/parse.moon index 0403f333..d1a5fff1 100644 --- a/moonscript/parse.moon +++ b/moonscript/parse.moon @@ -292,11 +292,11 @@ build_grammar = wrap_env debug_grammar, (root) -> KeyValueList: KeyValue * (sym"," * KeyValue)^0 KeyValueLine: CheckIndent * KeyValueList * sym","^-1 - FnArgsDef: sym"(" * Ct(FnArgDefList^-1) * + FnArgsDef: sym"(" * White * Ct(FnArgDefList^-1) * (key"using" * Ct(NameList + Space * "nil") + Ct"") * - sym")" + Ct"" * Ct"" + White * sym")" + Ct"" * Ct"" - FnArgDefList: FnArgDef * (sym"," * FnArgDef)^0 * (sym"," * Ct(VarArg))^0 + Ct(VarArg) + FnArgDefList: FnArgDef * (sym"," * White * FnArgDef)^0 * (sym"," * White * Ct(VarArg))^0 + Ct(VarArg) FnArgDef: Ct((Name + SelfName) * (sym"=" * Exp)^-1) FunLit: FnArgsDef * diff --git a/spec/inputs/funcs.moon b/spec/inputs/funcs.moon index a6812255..faab1aff 100644 --- a/spec/inputs/funcs.moon +++ b/spec/inputs/funcs.moon @@ -95,5 +95,26 @@ f( -- +x = (a, + b) -> + print "what" + + +y = (a="hi", + b=23) -> + print "what" + +z = ( + a="hi", + b=23) -> + print "what" + + +j = (f,g,m, + a="hi", + b=23 +) -> + print "what" + nil diff --git a/spec/outputs/funcs.lua b/spec/outputs/funcs.lua index 02f4f756..1ce333dd 100644 --- a/spec/outputs/funcs.lua +++ b/spec/outputs/funcs.lua @@ -125,4 +125,37 @@ end)(), 10, 20) f()()(what)(function() return print("srue") end, 123) +x = function(a, b) + return print("what") +end +local y +y = function(a, b) + if a == nil then + a = "hi" + end + if b == nil then + b = 23 + end + return print("what") +end +local z +z = function(a, b) + if a == nil then + a = "hi" + end + if b == nil then + b = 23 + end + return print("what") +end +local j +j = function(f, g, m, a, b) + if a == nil then + a = "hi" + end + if b == nil then + b = 23 + end + return print("what") +end return nil \ No newline at end of file From a5abd2fe1ec6566f00d6660d4a27c070989af15a Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 25 Sep 2016 17:47:44 -0700 Subject: [PATCH 394/554] tests for ... in whitepace function def --- spec/inputs/funcs.moon | 16 ++++++++++++++++ spec/outputs/funcs.lua | 18 ++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/spec/inputs/funcs.moon b/spec/inputs/funcs.moon index faab1aff..37387f84 100644 --- a/spec/inputs/funcs.moon +++ b/spec/inputs/funcs.moon @@ -117,4 +117,20 @@ j = (f,g,m, print "what" +y = (a="hi", + b=23, + ...) -> + print "what" + + +y = (a="hi", + b=23, + ... +) -> + print "what" + + + + + nil diff --git a/spec/outputs/funcs.lua b/spec/outputs/funcs.lua index 1ce333dd..43cb9342 100644 --- a/spec/outputs/funcs.lua +++ b/spec/outputs/funcs.lua @@ -158,4 +158,22 @@ j = function(f, g, m, a, b) end return print("what") end +y = function(a, b, ...) + if a == nil then + a = "hi" + end + if b == nil then + b = 23 + end + return print("what") +end +y = function(a, b, ...) + if a == nil then + a = "hi" + end + if b == nil then + b = 23 + end + return print("what") +end return nil \ No newline at end of file From e698e180acbc774fdff6ea86388a2b82cbebc832 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 25 Sep 2016 17:52:05 -0700 Subject: [PATCH 395/554] newlines can be used to separte function argument declarations --- moonscript/parse.lua | 2 +- moonscript/parse.moon | 2 +- spec/inputs/funcs.moon | 22 ++++++++++++++++++++++ spec/outputs/funcs.lua | 31 +++++++++++++++++++++++++++++++ 4 files changed, 55 insertions(+), 2 deletions(-) diff --git a/moonscript/parse.lua b/moonscript/parse.lua index f3fda489..da6731e7 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -188,7 +188,7 @@ local build_grammar = wrap_env(debug_grammar, function(root) KeyValueList = KeyValue * (sym(",") * KeyValue) ^ 0, KeyValueLine = CheckIndent * KeyValueList * sym(",") ^ -1, FnArgsDef = sym("(") * White * Ct(FnArgDefList ^ -1) * (key("using") * Ct(NameList + Space * "nil") + Ct("")) * White * sym(")") + Ct("") * Ct(""), - FnArgDefList = FnArgDef * (sym(",") * White * FnArgDef) ^ 0 * (sym(",") * White * Ct(VarArg)) ^ 0 + Ct(VarArg), + FnArgDefList = FnArgDef * ((sym(",") + Break) * White * FnArgDef) ^ 0 * ((sym(",") + Break) * White * Ct(VarArg)) ^ 0 + Ct(VarArg), FnArgDef = Ct((Name + SelfName) * (sym("=") * Exp) ^ -1), FunLit = FnArgsDef * (sym("->") * Cc("slim") + sym("=>") * Cc("fat")) * (Body + Ct("")) / mark("fndef"), NameList = Name * (sym(",") * Name) ^ 0, diff --git a/moonscript/parse.moon b/moonscript/parse.moon index d1a5fff1..7fd5de6f 100644 --- a/moonscript/parse.moon +++ b/moonscript/parse.moon @@ -296,7 +296,7 @@ build_grammar = wrap_env debug_grammar, (root) -> (key"using" * Ct(NameList + Space * "nil") + Ct"") * White * sym")" + Ct"" * Ct"" - FnArgDefList: FnArgDef * (sym"," * White * FnArgDef)^0 * (sym"," * White * Ct(VarArg))^0 + Ct(VarArg) + FnArgDefList: FnArgDef * ((sym"," + Break) * White * FnArgDef)^0 * ((sym"," + Break) * White * Ct(VarArg))^0 + Ct(VarArg) FnArgDef: Ct((Name + SelfName) * (sym"=" * Exp)^-1) FunLit: FnArgsDef * diff --git a/spec/inputs/funcs.moon b/spec/inputs/funcs.moon index 37387f84..08a29b64 100644 --- a/spec/inputs/funcs.moon +++ b/spec/inputs/funcs.moon @@ -129,6 +129,28 @@ y = (a="hi", ) -> print "what" +-- + +args = (a + b) -> + print "what" + + +args = (a="hi" + b=23) -> + print "what" + +args = ( + a="hi" + b=23) -> + print "what" + + +args = (f,g,m + a="hi" + b=23 +) -> + print "what" diff --git a/spec/outputs/funcs.lua b/spec/outputs/funcs.lua index 43cb9342..f5e2cf3c 100644 --- a/spec/outputs/funcs.lua +++ b/spec/outputs/funcs.lua @@ -176,4 +176,35 @@ y = function(a, b, ...) end return print("what") end +local args +args = function(a, b) + return print("what") +end +args = function(a, b) + if a == nil then + a = "hi" + end + if b == nil then + b = 23 + end + return print("what") +end +args = function(a, b) + if a == nil then + a = "hi" + end + if b == nil then + b = 23 + end + return print("what") +end +args = function(f, g, m, a, b) + if a == nil then + a = "hi" + end + if b == nil then + b = 23 + end + return print("what") +end return nil \ No newline at end of file From b3e2aabf14c2407a2054579c830ea3c1c518221c Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 25 Sep 2016 18:10:53 -0700 Subject: [PATCH 396/554] start writing changelog --- CHANGELOG.md | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d2c2cdb7..e59823fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,64 @@ + +# MoonScript v0.5.0 (2016-X-XX) + +## Syntax updates + +### Function calls + +Function calls with parentheses can not have free whitespace around the +arguments. Additionally, a line break may be used in place of a comma: + +```moonscript +my_func( + "first arg" + => + print "some func" + + "third arg", "fourth arg" +) +``` + +### Function argument definitions + +Just like the function all update, function argument definitions have no +whitespace restrictions between arguments, and line breaks can be used to +separate arguments: + + +```moonscript +some_func = ( + name + type + action="print" +) => + print name, type, action +``` + +## Additions + +* `elseif` can be used part of an `unless` block (nymphium) +* `unless` conditional expression can contain an assignment like an `if` statement (#251) +* Lua 5.3 bitwise operator support (nymphium) (Kawahara Satoru) +* Makefile is Lua version agnostic (nymphium) +* Lint flag can be used with `moonc` watch mode (ChickenNuggers) +* Lint exits with status 1 if there was a problem detected (ChickenNuggers) +* Compiler can be used with lulpeg + +## Bug Fixes + +* Slice boundaries can be full expressions (#233) +* Destructure works when used as loop variable in comprehension (#236) +* Proper name local hoisting works for classes again (#287) +* Quoted table key literals can now be parsed when table declaration is in single line (#286) +* Fix an issue where `else` could get attached to wrong `if` statement (#276) +* Loop variables will no longer overwrite variables of the same name in the same scope (egonSchiele) +* A file being deleted will not crash polling watch mode (ChickenNuggers) +* The compiler will not try to compile a directory ending in `.moon` (Gskartwii) +* alt_getopt import works with modern version (Jon Allen) +* Code coverage not being able to find file from chunk name + + # MoonScript v0.4.0 (2015-12-06) ## Changes to `super` From c3f4e511c21afa7d2f9b6257f9d3805da65b0313 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 25 Sep 2016 18:19:40 -0700 Subject: [PATCH 397/554] version bump :full_moon_with_face: --- moonscript/version.lua | 2 +- moonscript/version.moon | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/moonscript/version.lua b/moonscript/version.lua index 45fa3c50..91f885aa 100644 --- a/moonscript/version.lua +++ b/moonscript/version.lua @@ -1,4 +1,4 @@ -local version = "0.4.0" +local version = "0.5.0" return { version = version, print_version = function() diff --git a/moonscript/version.moon b/moonscript/version.moon index 6f665e26..68c483e4 100644 --- a/moonscript/version.moon +++ b/moonscript/version.moon @@ -1,5 +1,5 @@ -version = "0.4.0" +version = "0.5.0" { version: version, From b8244cb0937dc62a87c0bcd573b7319bdf7eef89 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 25 Sep 2016 18:26:27 -0700 Subject: [PATCH 398/554] fix typo, add date --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e59823fb..dd9c43dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,12 @@ -# MoonScript v0.5.0 (2016-X-XX) +# MoonScript v0.5.0 (2016-9-25) ## Syntax updates ### Function calls -Function calls with parentheses can not have free whitespace around the +Function calls with parentheses can now have free whitespace around the arguments. Additionally, a line break may be used in place of a comma: ```moonscript From 2a9f16377b08f6e2ec51cd21a88b38cfac2d98f8 Mon Sep 17 00:00:00 2001 From: ryan Date: Mon, 26 Sep 2016 01:53:43 -0700 Subject: [PATCH 399/554] document new bitwise update assignment operators (#291) --- docs/reference.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/docs/reference.md b/docs/reference.md index 37e7871e..ce34721b 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -55,9 +55,9 @@ variable, or shadow an existing one. ## Update Assignment -`+=`, `-=`, `/=`, `*=`, `%=`, `..=`, `or=`, `and=` operators have been added -for updating and assigning at the same time. They are aliases for their -expanded equivalents. +`+=`, `-=`, `/=`, `*=`, `%=`, `..=`, `or=`, `and=`, `&=`, `|=`, `>>=`, and +`<<=` operators have been added for updating and assigning at the same time. +They are aliases for their expanded equivalents. ```moon x = 0 @@ -68,6 +68,12 @@ s ..= "world" b = false b and= true or false + +p = 50 +p &= 5 +p |= 3 +p >>= 3 +p <<= 3 ``` ## Comments From 669ca059633465753ba2ec1d11f76e4cbe03299a Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Mon, 3 Oct 2016 15:40:30 -0700 Subject: [PATCH 400/554] remove accidental print, fixes #295 --- moonscript/cmd/watchers.lua | 1 - moonscript/cmd/watchers.moon | 1 - 2 files changed, 2 deletions(-) diff --git a/moonscript/cmd/watchers.lua b/moonscript/cmd/watchers.lua index 651011b2..7e266b8d 100644 --- a/moonscript/cmd/watchers.lua +++ b/moonscript/cmd/watchers.lua @@ -203,7 +203,6 @@ do local file file = _des_0[1] local time = lfs.attributes(file, "modification") - print(file, time) if not (time) then mod_time[file] = nil _continue_0 = true diff --git a/moonscript/cmd/watchers.moon b/moonscript/cmd/watchers.moon index b021e80e..c147fc5e 100644 --- a/moonscript/cmd/watchers.moon +++ b/moonscript/cmd/watchers.moon @@ -86,7 +86,6 @@ class SleepWatcher extends Watcher while true for {file} in *@file_list time = lfs.attributes file, "modification" - print file, time unless time -- file no longer exists mod_time[file] = nil continue From baf44fd7f79dbdf9261c349dae61267c7df45ff5 Mon Sep 17 00:00:00 2001 From: Lassi Kortela Date: Sat, 8 Oct 2016 20:49:36 +0300 Subject: [PATCH 401/554] mention emacs mode in readme (#297) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index fb79f111..8dd57d42 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ branch](https://github.com/leafo/moonscript/tree/binaries) * [Vim](https://github.com/leafo/moonscript-vim) * [Textadept](https://github.com/leafo/moonscript-textadept) * [Sublime/Textmate](https://github.com/leafo/moonscript-tmbundle) +* [Emacs](https://github.com/k2052/moonscript-mode) ## License (MIT) From 9e1ad7fe53b6eb24da84f3f11f23c6739b3ec970 Mon Sep 17 00:00:00 2001 From: LudwikJaniuk Date: Sun, 23 Oct 2016 02:33:25 +0200 Subject: [PATCH 402/554] Specify that directories are also accepted (#294) Small change in wording to make it a bit clearer that you can provide directory names to moonc, not just file names. --- bin/moonc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/moonc b/bin/moonc index dfd56969..61416327 100755 --- a/bin/moonc +++ b/bin/moonc @@ -9,7 +9,7 @@ local opts, ind = alt_getopt.get_opts(arg, "lvhwt:o:pTXb", { local read_stdin = arg[1] == "--" -local help = [[Usage: %s [options] files... +local help = [[Usage: %s [options] files/directories... -h Print this message -w Watch file/directory From 0b4a42437898edb1f252c3092b3e5ec2459a9aa2 Mon Sep 17 00:00:00 2001 From: "Lord Niels N. Horn" Date: Sun, 23 Oct 2016 22:50:57 +0200 Subject: [PATCH 403/554] Correct 'repl' to 'REPL' (#301) --- bin/moon.moon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/moon.moon b/bin/moon.moon index eb36eab5..4f02431a 100644 --- a/bin/moon.moon +++ b/bin/moon.moon @@ -47,7 +47,7 @@ run = -> script_fname = arg[ind] unless script_fname - print_help "repl not yet supported" + print_help "REPL not yet supported" new_arg = { [-1]: arg[0], From 0998331a5d717ab7ae26f4d99cbdfa824f9d7e56 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 23 Oct 2016 13:51:31 -0700 Subject: [PATCH 404/554] rebuild #301 --- bin/moon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/moon b/bin/moon index 9b7593ba..e69d7a06 100755 --- a/bin/moon +++ b/bin/moon @@ -54,7 +54,7 @@ run = function() end local script_fname = arg[ind] if not (script_fname) then - print_help("repl not yet supported") + print_help("REPL not yet supported") end local new_arg = { [-1] = arg[0], From fc741a3c1e4712dea0ffd5c9c508b48c0f89ac04 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 22 Nov 2016 23:50:48 -0800 Subject: [PATCH 405/554] start building ast spec --- spec/compiler_spec.moon | 36 ++++++++++++++++++++++++++++++++++++ spec/factory.moon | 9 +++++++++ 2 files changed, 45 insertions(+) create mode 100644 spec/compiler_spec.moon create mode 100644 spec/factory.moon diff --git a/spec/compiler_spec.moon b/spec/compiler_spec.moon new file mode 100644 index 00000000..01233538 --- /dev/null +++ b/spec/compiler_spec.moon @@ -0,0 +1,36 @@ +import Block from require "moonscript.compile" +import ref from require "spec.factory" + +-- no transform step +class SimpleBlock extends Block + new: (...) => + super ... + @transform = { + value: (...) -> ... + statement: (...) -> ... + } + +value = require "moonscript.compile.value" + +describe "moonscript.compile", -> + compile_node = (node) -> + block = SimpleBlock! + block\add block\value node + lines = block._lines\flatten! + lines[#lines] = nil if lines[#lines] == "\n" + table.concat lines + + -- compiling lua ast + describe "value", -> + for {name, node, expected} in *{ + { + "ref" + -> {"ref", "hello_world"} + "hello_world" + } + } + it "compiles #{name}", -> + node = node! + assert.same expected, compile_node(node) + + diff --git a/spec/factory.moon b/spec/factory.moon new file mode 100644 index 00000000..5a1c4989 --- /dev/null +++ b/spec/factory.moon @@ -0,0 +1,9 @@ + +-- ast factory + +ref = (name="val") -> + {"ref", name} + +{ + :var +} From e75fceff68ff4167b051390eaa4ec5c6d842aae6 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 23 Nov 2016 00:04:31 -0800 Subject: [PATCH 406/554] more ast specs --- spec/compiler_spec.moon | 73 ++++++++++++++++++++++++++++++++++++++++- spec/factory.moon | 6 +++- 2 files changed, 77 insertions(+), 2 deletions(-) diff --git a/spec/compiler_spec.moon b/spec/compiler_spec.moon index 01233538..c1c9577d 100644 --- a/spec/compiler_spec.moon +++ b/spec/compiler_spec.moon @@ -1,5 +1,6 @@ import Block from require "moonscript.compile" -import ref from require "spec.factory" + +import ref, str from require "spec.factory" -- no transform step class SimpleBlock extends Block @@ -28,6 +29,76 @@ describe "moonscript.compile", -> -> {"ref", "hello_world"} "hello_world" } + + { + "explist" + -> { "explist", ref("a"), ref("b"), ref("c")} + "a, b, c" + } + + { + "parens" + -> { "parens", ref! } + "(val)" + } + + { + "string (single quote)" + -> {"string", "'", "Hello\\'s world"} + "'Hello\\'s world'" + } + + { + "string (double quote)" + -> {"string", '"', "Hello's world"} + [["Hello's world"]] + + } + + { + "string (lua)" + -> {"string", '[==[', "Hello's world"} + "[==[Hello's world]==]" + } + + { + "chain (single)" + -> {"chain", ref!} + "val" + } + + { + "chain (dot)" + -> {"chain", ref!, {"dot", "zone"} } + "val.zone" + } + + { + "chain (index)" + -> {"chain", ref!, {"index", ref("x") } } + "val[x]" + } + + + { + "chain (call)" + -> {"chain", ref!, {"call", { ref("arg") }} } + "val(arg)" + } + + { + "chain" + -> { + "chain" + ref! + {"dot", "one"} + {"index", str!} + {"colon", "two"} + {"call", { ref("arg") }} + } + 'val.one["dogzone"]:two(arg)' + } + } it "compiles #{name}", -> node = node! diff --git a/spec/factory.moon b/spec/factory.moon index 5a1c4989..a6f3d76c 100644 --- a/spec/factory.moon +++ b/spec/factory.moon @@ -4,6 +4,10 @@ ref = (name="val") -> {"ref", name} +str = (contents="dogzone", delim='"') -> + {"string", delim, contents} + { - :var + :ref + :str } From b367f7ed514967ced8d852df2658016827c3628d Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 23 Nov 2016 08:42:24 -0800 Subject: [PATCH 407/554] more ast --- spec/compiler_spec.moon | 90 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 83 insertions(+), 7 deletions(-) diff --git a/spec/compiler_spec.moon b/spec/compiler_spec.moon index c1c9577d..696e6bb9 100644 --- a/spec/compiler_spec.moon +++ b/spec/compiler_spec.moon @@ -30,12 +30,30 @@ describe "moonscript.compile", -> "hello_world" } + { + "number" + -> {"number", "14"} + "14" + } + + { + "minus" + -> {"minus", ref!} + "-val" + } + { "explist" -> { "explist", ref("a"), ref("b"), ref("c")} "a, b, c" } + { + "exp" + -> {"exp", ref("a"), "+", ref("b"), "!=", ref("c")} + "a + b ~= c" + } + { "parens" -> { "parens", ref! } @@ -61,6 +79,48 @@ describe "moonscript.compile", -> "[==[Hello's world]==]" } + { + "self" + -> {"self", ref!} + "self.val" + } + + { + "self_class" + -> {"self_class", ref!} + "self.__class.val" + } + + { + "self_class_colon" + -> {"self_class_colon", ref!} + "self.__class:val" + } + + { + "not" + -> {"not", ref!} + "not val" + } + + { + "length" + -> {"length", ref!} + "#val" + } + + { + "length" + -> {"length", ref!} + "#val" + } + + { + "bitnot" + -> {"bitnot", ref!} + "~val" + } + { "chain (single)" -> {"chain", ref!} @@ -89,16 +149,32 @@ describe "moonscript.compile", -> { "chain" -> { - "chain" - ref! - {"dot", "one"} - {"index", str!} - {"colon", "two"} - {"call", { ref("arg") }} - } + "chain" + ref! + {"dot", "one"} + {"index", str!} + {"colon", "two"} + {"call", { ref("arg") }} + } 'val.one["dogzone"]:two(arg)' } + { + "chain (self receiver)" + -> { + "chain" + {"self", ref!} + {"call", {ref "arg"} } + } + "self:val(arg)" + } + + { + "fndef (empty)" + -> {"fndef", {}, {}, "slim", {}} + "function() end" + } + } it "compiles #{name}", -> node = node! From 5ff168f9d9c4aa9c39f2082fb14d7950bae4dd5e Mon Sep 17 00:00:00 2001 From: Peter Melnichenko Date: Sat, 7 Jan 2017 01:52:05 +0400 Subject: [PATCH 408/554] Mention Loadkit requirement for tests in README.md (#315) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8dd57d42..029ad633 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Online demo/compiler at . ## Running Tests Tests are written in MoonScript and use [Busted](http://olivinelabs.com/busted/). -In order to run the tests you must have MoonScript installed. +In order to run the tests you must have MoonScript and [Loadkit](https://github.com/leafo/loadkit) installed. To run tests, execute from the root directory: From 39cff4ece3372ac9da62a5e6115006709159434b Mon Sep 17 00:00:00 2001 From: Ryan Tongol Date: Fri, 6 Jan 2017 15:43:33 -0800 Subject: [PATCH 409/554] update copyright years (#316) --- README.md | 4 ++-- docs/reference.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 029ad633..535525b1 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ branch](https://github.com/leafo/moonscript/tree/binaries) ## License (MIT) -Copyright (C) 2015 by Leaf Corcoran +Copyright (C) 2017 by Leaf Corcoran Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -64,4 +64,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. \ No newline at end of file +THE SOFTWARE. diff --git a/docs/reference.md b/docs/reference.md index ce34721b..9782f2ba 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -1565,7 +1565,7 @@ their written order you can add `local *` to the top of your file. # License (MIT) - Copyright (C) 2015 by Leaf Corcoran + Copyright (C) 2017 by Leaf Corcoran Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From dfef936a0cbda897d2f9512acdfe511e2f8a927b Mon Sep 17 00:00:00 2001 From: RyanSquared Date: Tue, 30 May 2017 00:14:03 -0500 Subject: [PATCH 410/554] bin/moon.moon: add support for argparse, remove support for alt-getopt --- bin/moon | 76 +++++++++++++++++++++++---------------------------- bin/moon.moon | 60 ++++++++++++++-------------------------- 2 files changed, 55 insertions(+), 81 deletions(-) diff --git a/bin/moon b/bin/moon index e69d7a06..ef3c2f2f 100755 --- a/bin/moon +++ b/bin/moon @@ -1,30 +1,39 @@ -#!/usr/bin/env lua -local alt_getopt = require("alt_getopt") +local argparse = require("argparse") local moonscript = require("moonscript.base") local util = require("moonscript.util") local errors = require("moonscript.errors") local unpack = util.unpack -local opts, ind = alt_getopt.get_opts(arg, "cvhd", { - version = "v", - help = "h" +local argparser = argparse()({ + name = "moon" }) -local help = [=[Usage: %s [options] [script [args]] - - -h Print this message - -d Disable stack trace rewriting - -c Collect and print code coverage - -v Print version -]=] +argparser:argument("script") +argparser:argument("args"):args("*") +argparser:option("-c --coverage", "Collect and print code coverage") +argparser:option("-d", "Disable stack trace rewriting") +argparser:option("-v --version", "Print version information") +local base = 0 +local _list_0 = arg +for _index_0 = 1, #_list_0 do + local flag = _list_0[_index_0] + base = base + 1 + if flag:sub(1, 1) ~= "-" then + break + end +end +local args = { + unpack(arg, 1, base) +} +local opts = argparser:parse(args) local print_err print_err = function(...) local msg = table.concat((function(...) local _accum_0 = { } local _len_0 = 1 - local _list_0 = { + local _list_1 = { ... } - for _index_0 = 1, #_list_0 do - local v = _list_0[_index_0] + for _index_0 = 1, #_list_1 do + local v = _list_1[_index_0] _accum_0[_len_0] = tostring(v) _len_0 = _len_0 + 1 end @@ -32,35 +41,18 @@ print_err = function(...) end)(...), "\t") return io.stderr:write(msg .. "\n") end -local print_help -print_help = function(err) - help = help:format(arg[0]) - if err then - print_err(err) - print_err(help) - else - print(help) - end - return os.exit() -end local run run = function() - if opts.h then - print_help() - end - if opts.v then + if opts.version then require("moonscript.version").print_version() os.exit() end - local script_fname = arg[ind] - if not (script_fname) then - print_help("REPL not yet supported") - end - local new_arg = { - [-1] = arg[0], - [0] = arg[ind], - select(ind + 1, unpack(arg)) + local script_fname = opts.script + args = { + unpack(arg, base + 1) } + args[-1] = arg[0] + args[0] = opts.script local moonscript_chunk, lua_parse_error local passed, err = pcall(function() moonscript_chunk, lua_parse_error = moonscript.loadfile(script_fname, { @@ -79,18 +71,19 @@ run = function() end os.exit(1) end - util.getfenv(moonscript_chunk).arg = new_arg + util.getfenv(moonscript_chunk).arg = args + print(args[-1], args[0], args[1]) local run_chunk run_chunk = function() moonscript.insert_loader() - moonscript_chunk(unpack(new_arg)) + moonscript_chunk(unpack(args)) return moonscript.remove_loader() end if opts.d then return run_chunk() end local err, trace, cov - if opts.c then + if opts.coverage then print("starting coverage") local coverage = require("moonscript.cmd.coverage") cov = coverage.CodeCoverage() @@ -119,4 +112,3 @@ run = function() end end return run() --- vim: set filetype=lua: diff --git a/bin/moon.moon b/bin/moon.moon index 4f02431a..71bdafb0 100644 --- a/bin/moon.moon +++ b/bin/moon.moon @@ -1,5 +1,4 @@ - -alt_getopt = require "alt_getopt" +argparse = require "argparse" moonscript = require "moonscript.base" util = require "moonscript.util" @@ -7,53 +6,36 @@ errors = require "moonscript.errors" unpack = util.unpack -opts, ind = alt_getopt.get_opts arg, "cvhd", { - version: "v" - help: "h" -} - -help = [=[Usage: %s [options] [script [args]] +argparser = argparse! name: "moon" - -h Print this message - -d Disable stack trace rewriting - -c Collect and print code coverage - -v Print version -]=] +argparser\argument "script" +argparser\argument("args")\args "*" +argparser\option "-c --coverage", "Collect and print code coverage" +argparser\option "-d", "Disable stack trace rewriting" +argparser\option "-v --version", "Print version information" +base = 0 +for flag in *arg + base += 1 + break if flag\sub(1, 1) != "-" +args = {unpack arg, 1, base} +opts = argparser\parse args print_err = (...) -> msg = table.concat [tostring v for v in *{...}], "\t" io.stderr\write msg .. "\n" -print_help = (err) -> - help = help\format arg[0] - - if err - print_err err - print_err help - else - print help - - os.exit! - run = -> - if opts.h - print_help! - if opts.v + if opts.version require("moonscript.version").print_version! os.exit! - script_fname = arg[ind] - - unless script_fname - print_help "REPL not yet supported" + script_fname = opts.script - new_arg = { - [-1]: arg[0], - [0]: arg[ind], - select ind + 1, unpack arg - } + args = {unpack arg, base + 1} + args[-1] = arg[0] + args[0] = opts.script local moonscript_chunk, lua_parse_error @@ -74,11 +56,11 @@ run = -> os.exit 1 - util.getfenv(moonscript_chunk).arg = new_arg + util.getfenv(moonscript_chunk).arg = args run_chunk = -> moonscript.insert_loader! - moonscript_chunk unpack new_arg + moonscript_chunk unpack args moonscript.remove_loader! if opts.d @@ -86,7 +68,7 @@ run = -> local err, trace, cov - if opts.c + if opts.coverage print "starting coverage" coverage = require "moonscript.cmd.coverage" cov = coverage.CodeCoverage! From dd9661db93d3e6328af18e277a15cca0ae44ad1d Mon Sep 17 00:00:00 2001 From: RyanSquared Date: Tue, 30 May 2017 00:14:20 -0500 Subject: [PATCH 411/554] bin/moonc: add support for argparse, remove support for alt-getopt --- bin/moonc | 92 +++++++++++++++++++------------------------------------ 1 file changed, 31 insertions(+), 61 deletions(-) diff --git a/bin/moonc b/bin/moonc index 61416327..f3aad57a 100755 --- a/bin/moonc +++ b/bin/moonc @@ -1,50 +1,38 @@ #!/usr/bin/env lua -local alt_getopt = require "alt_getopt" +local argparse = require "argparse" local lfs = require "lfs" -local opts, ind = alt_getopt.get_opts(arg, "lvhwt:o:pTXb", { - print = "p", tree = "T", version = "v", help = "h", lint = "l" -}) - -local read_stdin = arg[1] == "--" - -local help = [[Usage: %s [options] files/directories... - - -h Print this message - -w Watch file/directory - -t path Specify where to place compiled files - -o file Write output to file - -p Write output to standard out - -T Write parse tree instead of code (to stdout) - -X Write line rewrite map instead of code (to stdout) - -l Perform lint on the file instead of compiling - -b Dump parse and compile time (doesn't write output) - -v Print version +local parser = argparse() + +parser:flag("-l --lint", "Perform a lint on the file instead of compiling") +parser:flag("-v --version", "Print version") +parser:flag("-w --watch", "Watch file/directory for updates") +parser:mutex( + parser:flag("-t --output-to", "Specify where to place compiled files"), + parser:flag("-o", "Write output to file"):args(1), + parser:flag("-p", "Write output to standard output"), + parser:flag("-T", "Write parse tree instead of code (to stdout)"), + parser:flag("-b", "Write parse and compile time instead of code(to stdout)"), + parser:flag("-X", "Write line rewrite map instead of code (to stdout)") +) +parser:flag("-", + "Read from standard in, print to standard out (Must be only argument)") + +local read_stdin = arg[1] == "--" -- luacheck: ignore 113 + +if not read_stdin then + parser:argument("file/directory"):args("+") +end - -- Read from standard in, print to standard out - (Must be first and only argument) -]] +local opts = parser:parse() -if opts.v then +if opts.version then local v = require "moonscript.version" v.print_version() os.exit() end -function print_help(err) - local help_msg = help:format(arg[0]) - - if err then - io.stderr:write("Error: ".. err .. "\n") - io.stderr:write(help_msg .. "\n") - os.exit(1) - else - print(help_msg) - os.exit(0) - end -end - function log_msg(...) if not opts.p then io.stderr:write(table.concat({...}, " ") .. "\n") @@ -53,10 +41,7 @@ end local moonc = require("moonscript.cmd.moonc") local util = require "moonscript.util" -local mkdir = moonc.mkdir local normalize_dir = moonc.normalize_dir -local parse_dir = moonc.parse_dir -local parse_file = moonc.parse_file local compile_and_write = moonc.compile_and_write local path_to_target = moonc.path_to_target @@ -102,23 +87,19 @@ local function get_files(fname, files) for _, sub_fname in ipairs(scan_directory(fname)) do table.insert(files, { sub_fname, - path_to_target(sub_fname, opts.t, fname) + path_to_target(sub_fname, opts.output_to, fname) }) end else table.insert(files, { fname, - path_to_target(fname, opts.t) + path_to_target(fname, opts.output_to) }) end return files end -if opts.h then - print_help() -end - if read_stdin then local parse = require "moonscript.parse" local compile = require "moonscript.compile" @@ -137,14 +118,7 @@ if read_stdin then os.exit() end -local inputs = {} -for i = ind, #arg do - table.insert(inputs, arg[i]) -end - -if #inputs == 0 then - print_help("No files specified") -end +local inputs = opts["file/directory"] local files = {} for _, input in ipairs(inputs) do @@ -155,10 +129,6 @@ files = remove_dups(files, function(f) return f[2] end) -if opts.o and #files > 1 then - print_help("-o can not be used with multiple input files") -end - -- returns an iterator that returns files that have been updated local function create_watcher(files) local watchers = require("moonscript.cmd.watchers") @@ -170,10 +140,10 @@ local function create_watcher(files) return watchers.SleepWatcher(files):each_update() end -if opts.w then +if opts.watch then -- build function to check for lint or compile in watch local handle_file - if opts.l then + if opts.lint then local lint = require "moonscript.cmd.lint" handle_file = lint.lint_file else @@ -199,7 +169,7 @@ if opts.w then end local success, err = handle_file(fname, target) - if opts.l then + if opts.lint then if success then io.stderr:write(success .. "\n\n") elseif err then @@ -218,7 +188,7 @@ if opts.w then end io.stderr:write("\nQuitting...\n") -elseif opts.l then +elseif opts.lint then local has_linted_with_error; local lint = require "moonscript.cmd.lint" for _, tuple in pairs(files) do From 6f332a45592073a794087cd5a8b8e92f7d66ceb2 Mon Sep 17 00:00:00 2001 From: RyanSquared Date: Tue, 30 May 2017 00:15:46 -0500 Subject: [PATCH 412/554] moonscript-dev-1.rockspec: replace alt-getopt with argparse --- moonscript-dev-1.rockspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/moonscript-dev-1.rockspec b/moonscript-dev-1.rockspec index c4388d0a..8970e306 100644 --- a/moonscript-dev-1.rockspec +++ b/moonscript-dev-1.rockspec @@ -16,7 +16,7 @@ description = { dependencies = { "lua >= 5.1", "lpeg >= 0.10, ~= 0.11", - "alt-getopt >= 0.7", + "argparse >= 0.5", "luafilesystem >= 1.5" } From fcc937ad39a0649eb782b1de0ebe3272362fd310 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Mon, 16 Oct 2017 16:19:08 -0700 Subject: [PATCH 413/554] rebuild moon --- bin/moon | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/moon b/bin/moon index ef3c2f2f..5e5e4251 100755 --- a/bin/moon +++ b/bin/moon @@ -1,3 +1,4 @@ +#!/usr/bin/env lua local argparse = require("argparse") local moonscript = require("moonscript.base") local util = require("moonscript.util") @@ -72,7 +73,6 @@ run = function() os.exit(1) end util.getfenv(moonscript_chunk).arg = args - print(args[-1], args[0], args[1]) local run_chunk run_chunk = function() moonscript.insert_loader() @@ -112,3 +112,4 @@ run = function() end end return run() +-- vim: set filetype=lua: From 9e36baa435edfaffb11ec8084aa439b7426ba275 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Mon, 16 Oct 2017 17:13:55 -0700 Subject: [PATCH 414/554] lift expressions from chain indexes on update operator, fixes #185 --- moonscript/transform/statement.lua | 69 ++++++++++++++++++++++++++++- moonscript/transform/statement.moon | 30 ++++++++++++- spec/inputs/syntax.moon | 4 ++ spec/outputs/syntax.lua | 6 +++ 4 files changed, 107 insertions(+), 2 deletions(-) diff --git a/moonscript/transform/statement.lua b/moonscript/transform/statement.lua index 7303666a..edeab697 100644 --- a/moonscript/transform/statement.lua +++ b/moonscript/transform/statement.lua @@ -353,18 +353,85 @@ return Transformer({ if not op_final then error("Unknown op: " .. op) end + local lifted + if ntype(name) == "chain" then + lifted = { } + local new_chain + do + local _accum_0 = { } + local _len_0 = 1 + for _index_0 = 3, #name do + local part = name[_index_0] + if ntype(part) == "index" then + local proxy = NameProxy("update") + table.insert(lifted, { + proxy, + part[2] + }) + _accum_0[_len_0] = { + "index", + proxy + } + else + _accum_0[_len_0] = part + end + _len_0 = _len_0 + 1 + end + new_chain = _accum_0 + end + if next(lifted) then + name = { + name[1], + name[2], + unpack(new_chain) + } + end + end if not (value_is_singular(exp)) then exp = { "parens", exp } end - return build.assign_one(name, { + local out = build.assign_one(name, { "exp", name, op_final, exp }) + if lifted and next(lifted) then + local names + do + local _accum_0 = { } + local _len_0 = 1 + for _index_0 = 1, #lifted do + local l = lifted[_index_0] + _accum_0[_len_0] = l[1] + _len_0 = _len_0 + 1 + end + names = _accum_0 + end + local values + do + local _accum_0 = { } + local _len_0 = 1 + for _index_0 = 1, #lifted do + local l = lifted[_index_0] + _accum_0[_len_0] = l[2] + _len_0 = _len_0 + 1 + end + values = _accum_0 + end + out = build.group({ + { + "assign", + names, + values + }, + out + }) + end + return out end, import = function(self, node) local names, source = unpack(node, 2) diff --git a/moonscript/transform/statement.moon b/moonscript/transform/statement.moon index f5cf3a54..2e4b8e83 100644 --- a/moonscript/transform/statement.moon +++ b/moonscript/transform/statement.moon @@ -229,9 +229,37 @@ Transformer { update: (node) => name, op, exp = unpack node, 2 op_final = op\match "^(.+)=$" + error "Unknown op: "..op if not op_final + + local lifted + + if ntype(name) == "chain" + lifted = {} + new_chain = for part in *name[3,] + if ntype(part) == "index" + proxy = NameProxy "update" + table.insert lifted, { proxy, part[2] } + { "index", proxy } + else + part + + if next lifted + name = {name[1], name[2], unpack new_chain} + exp = {"parens", exp} unless value_is_singular exp - build.assign_one name, {"exp", name, op_final, exp} + out = build.assign_one name, {"exp", name, op_final, exp} + + if lifted and next lifted + names = [l[1] for l in *lifted] + values = [l[2] for l in *lifted] + + out = build.group { + {"assign", names, values} + out + } + + out import: (node) => names, source = unpack node, 2 diff --git a/spec/inputs/syntax.moon b/spec/inputs/syntax.moon index 7b49d04b..854f6297 100644 --- a/spec/inputs/syntax.moon +++ b/spec/inputs/syntax.moon @@ -158,6 +158,10 @@ hello ..= "world" @@something += 10 @something += 10 +a["hello"] += 10 +a["hello#{tostring ff}"] += 10 +a[four].x += 10 + x = 0 (if ntype(v) == "fndef" then x += 1) for v in *values diff --git a/spec/outputs/syntax.lua b/spec/outputs/syntax.lua index bf323195..fef1a739 100644 --- a/spec/outputs/syntax.lua +++ b/spec/outputs/syntax.lua @@ -162,6 +162,12 @@ local m = m % 2 local hello = hello .. "world" self.__class.something = self.__class.something + 10 self.something = self.something + 10 +local _update_0 = "hello" +a[_update_0] = a[_update_0] + 10 +local _update_1 = "hello" .. tostring(tostring(ff)) +a[_update_1] = a[_update_1] + 10 +local _update_2 = four +a[_update_2].x = a[_update_2].x + 10 x = 0 local _list_0 = values for _index_0 = 1, #_list_0 do From 491f2352a238c4cbfe141c6aa80b3eb4cc9713f5 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 2 Feb 2018 21:55:21 -0800 Subject: [PATCH 415/554] add suppor tfor transform module --- bin/moonc | 4 +++- moonscript/cmd/moonc.lua | 6 ++++++ moonscript/cmd/moonc.moon | 3 +++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/bin/moonc b/bin/moonc index f3aad57a..e8086703 100755 --- a/bin/moonc +++ b/bin/moonc @@ -8,9 +8,10 @@ local parser = argparse() parser:flag("-l --lint", "Perform a lint on the file instead of compiling") parser:flag("-v --version", "Print version") parser:flag("-w --watch", "Watch file/directory for updates") +parser:option("--transform", "Transform syntax tree with module") parser:mutex( parser:flag("-t --output-to", "Specify where to place compiled files"), - parser:flag("-o", "Write output to file"):args(1), + parser:option("-o", "Write output to file"), parser:flag("-p", "Write output to standard output"), parser:flag("-T", "Write parse tree instead of code (to stdout)"), parser:flag("-b", "Write parse and compile time instead of code(to stdout)"), @@ -218,6 +219,7 @@ else benchmark = opts.b, show_posmap = opts.X, show_parse_tree = opts.T, + transform_module = opts.transform }) if not success then diff --git a/moonscript/cmd/moonc.lua b/moonscript/cmd/moonc.lua index 54600998..09ac3c78 100644 --- a/moonscript/cmd/moonc.lua +++ b/moonscript/cmd/moonc.lua @@ -81,6 +81,12 @@ compile_file_text = function(text, opts) if opts.benchmark then compile_time = gettime() end + do + local mod = opts.transform_module + if mod then + tree = assert(require(mod)(tree)) + end + end local code, posmap_or_err, err_pos = compile.tree(tree) if not (code) then return nil, compile.format_error(posmap_or_err, err_pos, text) diff --git a/moonscript/cmd/moonc.moon b/moonscript/cmd/moonc.moon index b2e92e63..ba59b06c 100644 --- a/moonscript/cmd/moonc.moon +++ b/moonscript/cmd/moonc.moon @@ -84,6 +84,9 @@ compile_file_text = (text, opts={}) -> compile_time = if opts.benchmark gettime! + if mod = opts.transform_module + tree = assert require(mod) tree + code, posmap_or_err, err_pos = compile.tree tree unless code From 9cba69b114c77028db365edfae02fe818dcd7f8b Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 13 Apr 2018 11:09:19 -0700 Subject: [PATCH 416/554] remove built printout when running comipiler on single file --- bin/moonc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/bin/moonc b/bin/moonc index e8086703..50c3c331 100755 --- a/bin/moonc +++ b/bin/moonc @@ -225,9 +225,7 @@ else if not success then io.stderr:write(fname .. "\t" .. err .. "\n") os.exit(1) - elseif success == "build" then - log_msg("Built", fname) - end + else end end From 57e4f984cbff45137ffe9bbecbd3dfabb7a0d871 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Mon, 30 Apr 2018 18:20:51 -0700 Subject: [PATCH 417/554] woops --- bin/moonc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/moonc b/bin/moonc index 50c3c331..195112c5 100755 --- a/bin/moonc +++ b/bin/moonc @@ -225,7 +225,7 @@ else if not success then io.stderr:write(fname .. "\t" .. err .. "\n") os.exit(1) - else + end end end From 61b825fa5a8614782c7b4808678ae877da70ff6e Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Mon, 30 Apr 2018 18:21:40 -0700 Subject: [PATCH 418/554] dump tree doesn't print by default --- moonscript/cmd/moonc.lua | 6 ++++-- moonscript/cmd/moonc.moon | 6 ++++-- moonscript/dump.lua | 2 +- moonscript/dump.moon | 2 +- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/moonscript/cmd/moonc.lua b/moonscript/cmd/moonc.lua index 09ac3c78..e7618ef8 100644 --- a/moonscript/cmd/moonc.lua +++ b/moonscript/cmd/moonc.lua @@ -74,7 +74,7 @@ compile_file_text = function(text, opts) end if opts.show_parse_tree then local dump = require("moonscript.dump") - dump.tree(tree) + print(dump.tree(tree)) return true end local compile_time @@ -84,7 +84,9 @@ compile_file_text = function(text, opts) do local mod = opts.transform_module if mod then - tree = assert(require(mod)(tree)) + local file = assert(loadfile(mod)) + local fn = assert(file()) + tree = assert(fn(tree)) end end local code, posmap_or_err, err_pos = compile.tree(tree) diff --git a/moonscript/cmd/moonc.moon b/moonscript/cmd/moonc.moon index ba59b06c..3e05bb07 100644 --- a/moonscript/cmd/moonc.moon +++ b/moonscript/cmd/moonc.moon @@ -78,14 +78,16 @@ compile_file_text = (text, opts={}) -> if opts.show_parse_tree dump = require "moonscript.dump" - dump.tree tree + print dump.tree tree return true compile_time = if opts.benchmark gettime! if mod = opts.transform_module - tree = assert require(mod) tree + file = assert loadfile mod + fn = assert file! + tree = assert fn tree code, posmap_or_err, err_pos = compile.tree tree diff --git a/moonscript/dump.lua b/moonscript/dump.lua index 1496ed43..1622f38c 100644 --- a/moonscript/dump.lua +++ b/moonscript/dump.lua @@ -32,7 +32,7 @@ tree = function(block) local _list_0 = block for _index_0 = 1, #_list_0 do local value = _list_0[_index_0] - print(flat_value(value)) + flat_value(value) end end return { diff --git a/moonscript/dump.moon b/moonscript/dump.moon index a6373daa..e651c22c 100644 --- a/moonscript/dump.moon +++ b/moonscript/dump.moon @@ -12,7 +12,7 @@ value = (op) -> flat_value op tree = (block) -> - print flat_value value for value in *block + flat_value value for value in *block { :value, :tree } From ff437509f1fd63b58ea3c00fb51a10be5666dc23 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Mon, 30 Apr 2018 18:24:51 -0700 Subject: [PATCH 419/554] maybe actually make this work correctly --- moonscript/dump.lua | 15 ++++++++++----- moonscript/dump.moon | 2 +- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/moonscript/dump.lua b/moonscript/dump.lua index 1622f38c..26cdd7a3 100644 --- a/moonscript/dump.lua +++ b/moonscript/dump.lua @@ -29,11 +29,16 @@ value = function(op) end local tree tree = function(block) - local _list_0 = block - for _index_0 = 1, #_list_0 do - local value = _list_0[_index_0] - flat_value(value) - end + return table.concat((function() + local _accum_0 = { } + local _len_0 = 1 + for _index_0 = 1, #block do + local value = block[_index_0] + _accum_0[_len_0] = flat_value(value) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)(), "\n") end return { value = value, diff --git a/moonscript/dump.moon b/moonscript/dump.moon index e651c22c..6fbeb375 100644 --- a/moonscript/dump.moon +++ b/moonscript/dump.moon @@ -12,7 +12,7 @@ value = (op) -> flat_value op tree = (block) -> - flat_value value for value in *block + table.concat [flat_value value for value in *block], "\n" { :value, :tree } From dd2d041b5e35ac89bee450e84ed5f58dfd6dbe39 Mon Sep 17 00:00:00 2001 From: leaf Date: Thu, 7 Jun 2018 21:43:07 -0700 Subject: [PATCH 420/554] add link to discord --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 535525b1..8f7e42b0 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,10 @@ See . Online demo/compiler at . +## Join Our Community + +We just created a Discord for those interested in MoonScript. You can join us here: + ## Running Tests Tests are written in MoonScript and use [Busted](http://olivinelabs.com/busted/). From bf16c518ebb2c67eee05dc64e8e7e2bb7ab9e2ae Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 25 Jan 2019 18:45:27 -0800 Subject: [PATCH 421/554] add docs for syntax tranformer --- docs/command_line.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/docs/command_line.md b/docs/command_line.md index 31fe48ee..f0e5d4b2 100644 --- a/docs/command_line.md +++ b/docs/command_line.md @@ -130,6 +130,23 @@ compiled automatically. A full list of flags can be seen by passing the `-h` or `--help` flag. +### Syntax Transformer + +A syntax transformer is a function that manipulates MoonScript code before +compiling to Lua. It operates on the parsed AST (Abstract Syntax Tree). It can +be used to implement macros, change syntax, optimize code, among other things. +You specify the name of a Lua module. This module must return a single function +(or callable object) that takes AST as an argument, and returns the new AST. + +```bash +moonc --transform my_transfomer my_script.moon +``` + +The transform can fail by returning `nil` and an error message. MoonScript AST +is currently undocumented, so you'll have to experiment by printing out the AST +to see how to make changes. MoonScript AST is made up of standard Lua tables +that are nested. + ### Linter `moonc` contains a [lint][1] tool for statically detecting potential problems From d64467d070c3ebf4168e546c967f864d2e7871ef Mon Sep 17 00:00:00 2001 From: Shemar McLean <16985079+Shemar32@users.noreply.github.com> Date: Sun, 17 Feb 2019 14:12:28 -0500 Subject: [PATCH 422/554] "-t --output-to" should be an option not a flag --- bin/moonc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/moonc b/bin/moonc index 195112c5..015979ad 100755 --- a/bin/moonc +++ b/bin/moonc @@ -10,7 +10,7 @@ parser:flag("-v --version", "Print version") parser:flag("-w --watch", "Watch file/directory for updates") parser:option("--transform", "Transform syntax tree with module") parser:mutex( - parser:flag("-t --output-to", "Specify where to place compiled files"), + parser:option("-t --output-to", "Specify where to place compiled files"), parser:option("-o", "Write output to file"), parser:flag("-p", "Write output to standard output"), parser:flag("-T", "Write parse tree instead of code (to stdout)"), From 29a780ecc4ea874f9593e51c228ed86dadc91ceb Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Mon, 16 Sep 2019 11:51:00 -0700 Subject: [PATCH 423/554] add twitch link --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 8f7e42b0..74396dfd 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,8 @@ [![Build Status](https://travis-ci.org/leafo/moonscript.svg?branch=master)](https://travis-ci.org/leafo/moonscript) [![Build status](https://ci.appveyor.com/api/projects/status/f5prpi4wvytul290/branch/binaries?svg=true)](https://ci.appveyor.com/project/leafo/moonscript/branch/binaries) +[![](http://leafo.net/dump/twitch-banner.svg)](https://www.twitch.tv/moonscript) + MoonScript is a programmer friendly language that compiles into [Lua](http://www.lua.org/). It gives you the power of the fastest scripting language combined with a rich set of features. It runs on Lua 5.1 and above, From dba4b10a4559e0efaaabeee4d82a34eab5311e88 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 26 Sep 2019 10:25:01 -0700 Subject: [PATCH 424/554] exit with error code when code run with moon fails --- bin/moon | 5 +++-- bin/moon.moon | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/bin/moon b/bin/moon index 5e5e4251..75f2156d 100755 --- a/bin/moon +++ b/bin/moon @@ -97,13 +97,14 @@ run = function() local truncated = errors.truncate_traceback(util.trim(trace)) local rewritten = errors.rewrite_traceback(truncated, err) if rewritten then - return print_err(rewritten) + print_err(rewritten) else - return print_err(table.concat({ + print_err(table.concat({ err, util.trim(trace) }, "\n")) end + return os.exit(1) else if cov then cov:stop() diff --git a/bin/moon.moon b/bin/moon.moon index 71bdafb0..94601d57 100644 --- a/bin/moon.moon +++ b/bin/moon.moon @@ -90,6 +90,7 @@ run = -> err, util.trim trace }, "\n" + os.exit 1 else if cov cov\stop! From 8c8f0874dfac549e47f95263a8c29b96ccc90ef5 Mon Sep 17 00:00:00 2001 From: jakbyte Date: Sun, 2 Feb 2020 13:57:54 -0500 Subject: [PATCH 425/554] README: Update links to be HTTPS (#393) * README: Update links to be HTTPS * Update Twitch link to use HTTPS --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 74396dfd..973a143c 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,20 @@ # MoonScript -[![MoonScript](http://leafo.net/dump/sailormoonscript.png)](http://moonscript.org) +[![MoonScript](https://leafo.net/dump/sailormoonscript.png)](https://moonscript.org) [![Build Status](https://travis-ci.org/leafo/moonscript.svg?branch=master)](https://travis-ci.org/leafo/moonscript) [![Build status](https://ci.appveyor.com/api/projects/status/f5prpi4wvytul290/branch/binaries?svg=true)](https://ci.appveyor.com/project/leafo/moonscript/branch/binaries) -[![](http://leafo.net/dump/twitch-banner.svg)](https://www.twitch.tv/moonscript) +[![](https://leafo.net/dump/twitch-banner.svg)](https://www.twitch.tv/moonscript) MoonScript is a programmer friendly language that compiles into -[Lua](http://www.lua.org/). It gives you the power of the fastest scripting +[Lua](https://www.lua.org/). It gives you the power of the fastest scripting language combined with a rich set of features. It runs on Lua 5.1 and above, including alternative runtimes like LuaJIT. -See . +See . -Online demo/compiler at . +Online demo/compiler at . ## Join Our Community @@ -22,7 +22,7 @@ We just created a Discord for those interested in MoonScript. You can join us he ## Running Tests -Tests are written in MoonScript and use [Busted](http://olivinelabs.com/busted/). +Tests are written in MoonScript and use [Busted](https://olivinelabs.com/busted/). In order to run the tests you must have MoonScript and [Loadkit](https://github.com/leafo/loadkit) installed. To run tests, execute from the root directory: From 39a904d419bffe9aa206935b067c40ae724c4d99 Mon Sep 17 00:00:00 2001 From: Jaxson Van Doorn Date: Sun, 22 Jul 2018 00:43:49 -0700 Subject: [PATCH 426/554] Fix typo in argument defaults section --- docs/reference.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference.md b/docs/reference.md index 9782f2ba..48302fb7 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -195,7 +195,7 @@ func = (num) => @value + num It is possible to provide default values for the arguments of a function. An argument is determined to be empty if its value is `nil`. Any `nil` arguments -that have a default value will be replace before the body of the function is run. +that have a default value will be replaced before the body of the function is run. ```moon my_function = (name="something", height=100) -> From 532200dc136f3a1cd5ae59a76fcab47bdce82330 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 2 Feb 2020 10:56:20 -0800 Subject: [PATCH 427/554] update copyright year, closes #394 --- README.md | 2 +- docs/reference.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 973a143c..0c247ba8 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ branch](https://github.com/leafo/moonscript/tree/binaries) ## License (MIT) -Copyright (C) 2017 by Leaf Corcoran +Copyright (C) 2020 by Leaf Corcoran Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/docs/reference.md b/docs/reference.md index 48302fb7..b95e8faf 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -1565,7 +1565,7 @@ their written order you can add `local *` to the top of your file. # License (MIT) - Copyright (C) 2017 by Leaf Corcoran + Copyright (C) 2020 by Leaf Corcoran Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From aad0d2a0f6dfda14ee6db12136a55ec0dfbe11b5 Mon Sep 17 00:00:00 2001 From: Qais Patankar Date: Thu, 30 Apr 2020 17:10:01 +0100 Subject: [PATCH 428/554] docs: fix `line_tabel` typo --- docs/api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api.md b/docs/api.md index c59f6f70..56425264 100644 --- a/docs/api.md +++ b/docs/api.md @@ -83,7 +83,7 @@ table. If there are any errors then `nil` and the error message are returned. ```moononly import to_lua from require "moonscript.base" -lua_code, line_tabel = to_lua [[ +lua_code, line_table = to_lua [[ x = 124 print "hello world #{x}" ]] From 494387236eb4c0cad1338cfb3c6e63610d657691 Mon Sep 17 00:00:00 2001 From: Nathan DECHER Date: Thu, 30 Apr 2020 23:35:24 +0200 Subject: [PATCH 429/554] Fixed moonscript generating ambiguous lua after `import` when the next line starts with `(` --- moonscript/compile.lua | 3 +-- moonscript/compile.moon | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/moonscript/compile.lua b/moonscript/compile.lua index 0715b862..58390c2a 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -94,8 +94,7 @@ do end insert(buffer, l) if "string" == type(self[i + 1]) then - local lc = l:sub(-1) - if (lc == ")" or lc == "]") and self[i + 1]:sub(1, 1) == "(" then + if l:sub(-1) ~= ',' and l:sub(-3) ~= 'end' and self[i + 1]:sub(1, 1) == "(" then insert(buffer, ";") end end diff --git a/moonscript/compile.moon b/moonscript/compile.moon index a2b17fee..716c2c4e 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -71,8 +71,7 @@ class Lines -- insert breaks between ambiguous statements if "string" == type @[i + 1] - lc = l\sub(-1) - if (lc == ")" or lc == "]") and @[i + 1]\sub(1,1) == "(" + if l\sub(-1)!=',' and l\sub(-3)!='end' and @[i + 1]\sub(1,1) == "(" insert buffer, ";" insert buffer, "\n" From 4ff4077a21a8b296cf3bf8fd7a522febc67c2165 Mon Sep 17 00:00:00 2001 From: Nathan DECHER Date: Thu, 30 Apr 2020 23:37:36 +0200 Subject: [PATCH 430/554] Fixed tests to accommodate for the new semicolons --- spec/outputs/string.lua | 2 +- spec/outputs/syntax.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/outputs/string.lua b/spec/outputs/string.lua index 2d751d81..a928c5d3 100644 --- a/spec/outputs/string.lua +++ b/spec/outputs/string.lua @@ -26,7 +26,7 @@ local f = [[hello #{world} world]] a = 'hello #{hello} hello' b = '#{hello} hello' c = 'hello #{hello}' -local _ = "hello" +local _ = "hello"; ("hello"):format(1); ("hello"):format(1, 2, 3); ("hello"):format(1, 2, 3)(1, 2, 3); diff --git a/spec/outputs/syntax.lua b/spec/outputs/syntax.lua index fef1a739..52c5d88f 100644 --- a/spec/outputs/syntax.lua +++ b/spec/outputs/syntax.lua @@ -192,7 +192,7 @@ _ = 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 From 0ac82e3af5bbb299f8e2b4d542cb3a0daafaba6c Mon Sep 17 00:00:00 2001 From: Nathan DECHER Date: Thu, 30 Apr 2020 23:54:00 +0200 Subject: [PATCH 431/554] Added tests for the semicolon insertion --- spec/inputs/ambiguous.moon | 8 ++++++++ spec/inputs/ambiguous_tables.moon | 6 ++++++ spec/outputs/ambiguous.lua | 9 +++++++++ spec/outputs/ambiguous_tables.lua | 6 ++++++ 4 files changed, 29 insertions(+) create mode 100644 spec/inputs/ambiguous.moon create mode 100644 spec/inputs/ambiguous_tables.moon create mode 100644 spec/outputs/ambiguous.lua create mode 100644 spec/outputs/ambiguous_tables.lua diff --git a/spec/inputs/ambiguous.moon b/spec/inputs/ambiguous.moon new file mode 100644 index 00000000..66109c11 --- /dev/null +++ b/spec/inputs/ambiguous.moon @@ -0,0 +1,8 @@ +a = 'b' +c = d +(a b) c d +import c from d +(a b) c d +(c d) a b +a, b = c, d +(d a) c diff --git a/spec/inputs/ambiguous_tables.moon b/spec/inputs/ambiguous_tables.moon new file mode 100644 index 00000000..c2c7ea8c --- /dev/null +++ b/spec/inputs/ambiguous_tables.moon @@ -0,0 +1,6 @@ +x = { +hello +(one) +(two) +three() +} diff --git a/spec/outputs/ambiguous.lua b/spec/outputs/ambiguous.lua new file mode 100644 index 00000000..2330da40 --- /dev/null +++ b/spec/outputs/ambiguous.lua @@ -0,0 +1,9 @@ +local a = 'b' +local c = d; +(a(b))(c(d)) +c = d.c; +(a(b))(c(d)); +(c(d))(a(b)) +local b +a, b = c, d +return (d(a))(c) \ No newline at end of file diff --git a/spec/outputs/ambiguous_tables.lua b/spec/outputs/ambiguous_tables.lua new file mode 100644 index 00000000..8af0aaab --- /dev/null +++ b/spec/outputs/ambiguous_tables.lua @@ -0,0 +1,6 @@ +local x = { + hello, + (one), + (two), + three() +} \ No newline at end of file From df7b10335d8f78df6a9f062c3b32c3d278d3984d Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 22 Nov 2020 16:24:11 -0800 Subject: [PATCH 432/554] recompile --- moonscript/cmd/coverage.lua | 6 ++++-- moonscript/compile.lua | 3 ++- moonscript/parse/util.lua | 3 ++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/moonscript/cmd/coverage.lua b/moonscript/cmd/coverage.lua index bed561f8..43456301 100644 --- a/moonscript/cmd/coverage.lua +++ b/moonscript/cmd/coverage.lua @@ -82,7 +82,8 @@ do process_line = function(self, _, line_no) local debug_data = debug.getinfo(2, "S") local source = debug_data.source - self.line_counts[source][line_no] = self.line_counts[source][line_no] + 1 + local _update_0, _update_1 = source, line_no + self.line_counts[_update_0][_update_1] = self.line_counts[_update_0][_update_1] + 1 end, format_results = function(self) local line_table = require("moonscript.line_tables") @@ -103,7 +104,8 @@ do _continue_1 = true break end - positions[file][position] = positions[file][position] + count + local _update_0, _update_1 = file, position + positions[_update_0][_update_1] = positions[_update_0][_update_1] + count _continue_1 = true until true if not _continue_1 then diff --git a/moonscript/compile.lua b/moonscript/compile.lua index 58390c2a..66f4df59 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -438,7 +438,8 @@ do self.next:render(buffer) else if #self._lines == 0 and "string" == type(buffer[#buffer]) then - buffer[#buffer] = buffer[#buffer] .. (" " .. (unpack(Lines():add(self.footer)))) + local _update_0 = #buffer + buffer[_update_0] = buffer[_update_0] .. (" " .. (unpack(Lines():add(self.footer)))) else buffer:add(self._lines) buffer:add(self.footer) diff --git a/moonscript/parse/util.lua b/moonscript/parse/util.lua index 2687384b..3f02c8d5 100644 --- a/moonscript/parse/util.lua +++ b/moonscript/parse/util.lua @@ -50,7 +50,8 @@ show_line_position = function(str, pos, context) { } } for c in str:gmatch(".") do - lines[#lines] = lines[#lines] or { } + local _update_0 = #lines + lines[_update_0] = lines[_update_0] or { } table.insert(lines[#lines], c) if c == "\n" then lines[#lines + 1] = { } From 91b483323c1fa6b99d50f34bbe2180239b9e0d78 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 22 Nov 2020 16:27:50 -0800 Subject: [PATCH 433/554] add github actions workflow --- .github/workflows/spec.yml | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 .github/workflows/spec.yml diff --git a/.github/workflows/spec.yml b/.github/workflows/spec.yml new file mode 100644 index 00000000..7ddab019 --- /dev/null +++ b/.github/workflows/spec.yml @@ -0,0 +1,31 @@ +name: "spec" + +on: [push] + +jobs: + test: + strategy: + fail-fast: false + matrix: + luaVersion: ["5.1", "5.2", "5.3", "5.4", "luajit", "luajit-openresty"] + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@master + + - uses: leafo/gh-actions-lua@master + with: + luaVersion: ${{ matrix.luaVersion }} + + - uses: leafo/gh-actions-luarocks@master + + - name: build + run: | + luarocks install busted + luarocks install loadkit + luarocks make + + - name: test + run: | + busted -o utfTerminal From 2d4732981cac9c874d37233ef6ed8c8be1e8acf1 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 22 Nov 2020 16:38:49 -0800 Subject: [PATCH 434/554] test windows workflow --- .github/workflows/windows_exe.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .github/workflows/windows_exe.yml diff --git a/.github/workflows/windows_exe.yml b/.github/workflows/windows_exe.yml new file mode 100644 index 00000000..137e8934 --- /dev/null +++ b/.github/workflows/windows_exe.yml @@ -0,0 +1,11 @@ +name: "windows_exe" + +on: [push] + +jobs: + build: + runs-on: windows-latest + + steps: + - name: hello + run: Get-ChildItem From 6cdfba0add95fd96c32afdfa746515668816af89 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 22 Nov 2020 16:41:13 -0800 Subject: [PATCH 435/554] check out the code.. --- .github/workflows/windows_exe.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/windows_exe.yml b/.github/workflows/windows_exe.yml index 137e8934..8332cb18 100644 --- a/.github/workflows/windows_exe.yml +++ b/.github/workflows/windows_exe.yml @@ -7,5 +7,6 @@ jobs: runs-on: windows-latest steps: - - name: hello - run: Get-ChildItem + - uses: actions/checkout@master + - name: hello + run: Get-ChildItem From e869c408e48a83bd149a772d58f891a90c2f6abd Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 22 Nov 2020 16:43:43 -0800 Subject: [PATCH 436/554] update badge to github workflow --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0c247ba8..967b84f6 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,8 @@ [![MoonScript](https://leafo.net/dump/sailormoonscript.png)](https://moonscript.org) -[![Build Status](https://travis-ci.org/leafo/moonscript.svg?branch=master)](https://travis-ci.org/leafo/moonscript) [![Build status](https://ci.appveyor.com/api/projects/status/f5prpi4wvytul290/branch/binaries?svg=true)](https://ci.appveyor.com/project/leafo/moonscript/branch/binaries) + +[![spec](https://github.com/leafo/moonscript/workflows/spec/badge.svg)](https://github.com/leafo/moonscript/actions?query=workflow%3Aspec) [![Build status](https://ci.appveyor.com/api/projects/status/f5prpi4wvytul290/branch/binaries?svg=true)](https://ci.appveyor.com/project/leafo/moonscript/branch/binaries) [![](https://leafo.net/dump/twitch-banner.svg)](https://www.twitch.tv/moonscript) From 81b6394329625df6c475b42d7fd65853f55ec5b8 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 22 Nov 2020 16:44:28 -0800 Subject: [PATCH 437/554] remove travis --- .travis.yml | 23 -------- .travis/platform.sh | 15 ------ .travis/setenv_lua.sh | 3 -- .travis/setup_lua.sh | 122 ------------------------------------------ 4 files changed, 163 deletions(-) delete mode 100644 .travis.yml delete mode 100644 .travis/platform.sh delete mode 100644 .travis/setenv_lua.sh delete mode 100644 .travis/setup_lua.sh diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 4e96f64e..00000000 --- a/.travis.yml +++ /dev/null @@ -1,23 +0,0 @@ -language: c - -sudo: false - -env: - global: - - LUAROCKS=2.2.2 - matrix: - - LUA=lua5.1 - - LUA=lua5.2 - - LUA=lua5.3 - - LUA=luajit2.1 # current head of 2.1 branch - - LUA=luajit2.1 BUSTED="-o spec/coverage_output_handler.moon" - -before_install: - - source .travis/setenv_lua.sh - -install: - - luarocks install busted - - luarocks install loadkit - - luarocks make - -script: busted $BUSTED diff --git a/.travis/platform.sh b/.travis/platform.sh deleted file mode 100644 index 7259a7d6..00000000 --- a/.travis/platform.sh +++ /dev/null @@ -1,15 +0,0 @@ -if [ -z "${PLATFORM:-}" ]; then - PLATFORM=$TRAVIS_OS_NAME; -fi - -if [ "$PLATFORM" == "osx" ]; then - PLATFORM="macosx"; -fi - -if [ -z "$PLATFORM" ]; then - if [ "$(uname)" == "Linux" ]; then - PLATFORM="linux"; - else - PLATFORM="macosx"; - fi; -fi diff --git a/.travis/setenv_lua.sh b/.travis/setenv_lua.sh deleted file mode 100644 index 8d8c8255..00000000 --- a/.travis/setenv_lua.sh +++ /dev/null @@ -1,3 +0,0 @@ -export PATH=${PATH}:$HOME/.lua:$HOME/.local/bin:${TRAVIS_BUILD_DIR}/install/luarocks/bin -bash .travis/setup_lua.sh -eval `$HOME/.lua/luarocks path` diff --git a/.travis/setup_lua.sh b/.travis/setup_lua.sh deleted file mode 100644 index 6dcc0c6e..00000000 --- a/.travis/setup_lua.sh +++ /dev/null @@ -1,122 +0,0 @@ -#! /bin/bash - -# A script for setting up environment for travis-ci testing. -# Sets up Lua and Luarocks. -# LUA must be "lua5.1", "lua5.2" or "luajit". -# luajit2.0 - master v2.0 -# luajit2.1 - master v2.1 - -set -eufo pipefail - -LUAJIT_VERSION="2.0.4" -LUAJIT_BASE="LuaJIT-$LUAJIT_VERSION" - -source .travis/platform.sh - -LUA_HOME_DIR=$TRAVIS_BUILD_DIR/install/lua - -LR_HOME_DIR=$TRAVIS_BUILD_DIR/install/luarocks - -mkdir $HOME/.lua - -LUAJIT="no" - -if [ "$PLATFORM" == "macosx" ]; then - if [ "$LUA" == "luajit" ]; then - LUAJIT="yes"; - fi - if [ "$LUA" == "luajit2.0" ]; then - LUAJIT="yes"; - fi - if [ "$LUA" == "luajit2.1" ]; then - LUAJIT="yes"; - fi; -elif [ "$(expr substr $LUA 1 6)" == "luajit" ]; then - LUAJIT="yes"; -fi - -mkdir -p "$LUA_HOME_DIR" - -if [ "$LUAJIT" == "yes" ]; then - - if [ "$LUA" == "luajit" ]; then - curl --location https://github.com/LuaJIT/LuaJIT/archive/v$LUAJIT_VERSION.tar.gz | tar xz; - else - git clone https://github.com/LuaJIT/LuaJIT.git $LUAJIT_BASE; - fi - - cd $LUAJIT_BASE - - if [ "$LUA" == "luajit2.1" ]; then - git checkout v2.1; - # force the INSTALL_TNAME to be luajit - perl -i -pe 's/INSTALL_TNAME=.+/INSTALL_TNAME= luajit/' Makefile - fi - - make && make install PREFIX="$LUA_HOME_DIR" - - ln -s $LUA_HOME_DIR/bin/luajit $HOME/.lua/luajit - ln -s $LUA_HOME_DIR/bin/luajit $HOME/.lua/lua; - -else - - if [ "$LUA" == "lua5.1" ]; then - curl http://www.lua.org/ftp/lua-5.1.5.tar.gz | tar xz - cd lua-5.1.5; - elif [ "$LUA" == "lua5.2" ]; then - curl http://www.lua.org/ftp/lua-5.2.4.tar.gz | tar xz - cd lua-5.2.4; - elif [ "$LUA" == "lua5.3" ]; then - curl http://www.lua.org/ftp/lua-5.3.2.tar.gz | tar xz - cd lua-5.3.2; - fi - - # Build Lua without backwards compatibility for testing - perl -i -pe 's/-DLUA_COMPAT_(ALL|5_2)//' src/Makefile - make $PLATFORM - make INSTALL_TOP="$LUA_HOME_DIR" install; - - ln -s $LUA_HOME_DIR/bin/lua $HOME/.lua/lua - ln -s $LUA_HOME_DIR/bin/luac $HOME/.lua/luac; - -fi - -cd $TRAVIS_BUILD_DIR - -lua -v - -LUAROCKS_BASE=luarocks-$LUAROCKS - -curl --location http://luarocks.org/releases/$LUAROCKS_BASE.tar.gz | tar xz - -cd $LUAROCKS_BASE - -if [ "$LUA" == "luajit" ]; then - ./configure --lua-suffix=jit --with-lua-include="$LUA_HOME_DIR/include/luajit-2.0" --prefix="$LR_HOME_DIR"; -elif [ "$LUA" == "luajit2.0" ]; then - ./configure --lua-suffix=jit --with-lua-include="$LUA_HOME_DIR/include/luajit-2.0" --prefix="$LR_HOME_DIR"; -elif [ "$LUA" == "luajit2.1" ]; then - ./configure --lua-suffix=jit --with-lua-include="$LUA_HOME_DIR/include/luajit-2.1" --prefix="$LR_HOME_DIR"; -else - ./configure --with-lua="$LUA_HOME_DIR" --prefix="$LR_HOME_DIR" -fi - -make build && make install - -ln -s $LR_HOME_DIR/bin/luarocks $HOME/.lua/luarocks - -cd $TRAVIS_BUILD_DIR - -luarocks --version - -rm -rf $LUAROCKS_BASE - -if [ "$LUAJIT" == "yes" ]; then - rm -rf $LUAJIT_BASE; -elif [ "$LUA" == "lua5.1" ]; then - rm -rf lua-5.1.5; -elif [ "$LUA" == "lua5.2" ]; then - rm -rf lua-5.2.4; -elif [ "$LUA" == "lua5.3" ]; then - rm -rf lua-5.3.2; -fi From 804b32acde91549a6216ee170958c8cc48e65ebc Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 22 Nov 2020 16:48:18 -0800 Subject: [PATCH 438/554] more testing --- .github/workflows/windows_exe.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/windows_exe.yml b/.github/workflows/windows_exe.yml index 8332cb18..fef2b0f0 100644 --- a/.github/workflows/windows_exe.yml +++ b/.github/workflows/windows_exe.yml @@ -10,3 +10,12 @@ jobs: - uses: actions/checkout@master - name: hello run: Get-ChildItem + + - uses: msys2/setup-msys2@v2 + with: + install: gcc make + + - run: gcc -v + + + From d1b717d28aa96765e575b70bb258d8ddbe247ce7 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 22 Nov 2020 16:59:19 -0800 Subject: [PATCH 439/554] more windows test --- .github/workflows/windows_exe.yml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/windows_exe.yml b/.github/workflows/windows_exe.yml index fef2b0f0..3a05fa4f 100644 --- a/.github/workflows/windows_exe.yml +++ b/.github/workflows/windows_exe.yml @@ -8,14 +8,20 @@ jobs: steps: - uses: actions/checkout@master - - name: hello - run: Get-ChildItem + - uses: msys2/setup-msys2@v2 with: - install: gcc make + install: gcc make curl - run: gcc -v + - name: Setup Lua + - run: | + curl -O https://www.lua.org/ftp/lua-5.1.5.tar.gz + tar -xZf lua-5.1.5.tar.gz + + - name: list files + run: Get-ChildItem From 3d5b9ce007454ae358ec9eb6a859e9d30c924624 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 22 Nov 2020 17:01:02 -0800 Subject: [PATCH 440/554] syntax fix --- .github/workflows/windows_exe.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/windows_exe.yml b/.github/workflows/windows_exe.yml index 3a05fa4f..44b45168 100644 --- a/.github/workflows/windows_exe.yml +++ b/.github/workflows/windows_exe.yml @@ -14,14 +14,15 @@ jobs: with: install: gcc make curl - - run: gcc -v + - name: Show GCC + run: gcc -v - name: Setup Lua - - run: | + run: | curl -O https://www.lua.org/ftp/lua-5.1.5.tar.gz tar -xZf lua-5.1.5.tar.gz - - name: list files + - name: List Files run: Get-ChildItem From 4c6eb918eb1423d26a945192ba2102c2ae394d0e Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 22 Nov 2020 17:04:21 -0800 Subject: [PATCH 441/554] try to build lua --- .github/workflows/windows_exe.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/windows_exe.yml b/.github/workflows/windows_exe.yml index 44b45168..88e92821 100644 --- a/.github/workflows/windows_exe.yml +++ b/.github/workflows/windows_exe.yml @@ -21,6 +21,7 @@ jobs: run: | curl -O https://www.lua.org/ftp/lua-5.1.5.tar.gz tar -xZf lua-5.1.5.tar.gz + cd lua-5.1.5; make PLAT=mingw - name: List Files run: Get-ChildItem From 9cad63ab8b5b906a50258e99c0a6f25fbad0821d Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 22 Nov 2020 17:10:22 -0800 Subject: [PATCH 442/554] recurse --- .github/workflows/windows_exe.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/windows_exe.yml b/.github/workflows/windows_exe.yml index 88e92821..f499747a 100644 --- a/.github/workflows/windows_exe.yml +++ b/.github/workflows/windows_exe.yml @@ -24,6 +24,6 @@ jobs: cd lua-5.1.5; make PLAT=mingw - name: List Files - run: Get-ChildItem + run: Get-ChildItem -Recurse From 8ae336bd05a92b5bec0a57d7ed3a7785a119585e Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 22 Nov 2020 17:38:50 -0800 Subject: [PATCH 443/554] test running lua --- .github/workflows/windows_exe.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/windows_exe.yml b/.github/workflows/windows_exe.yml index f499747a..e170ebf1 100644 --- a/.github/workflows/windows_exe.yml +++ b/.github/workflows/windows_exe.yml @@ -26,4 +26,6 @@ jobs: - name: List Files run: Get-ChildItem -Recurse + - name: Run Lua + run: lua-5.1.5/src/lua.exe -v From da1b28b1da08be616f4a97993e802e5163b1676e Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 22 Nov 2020 17:45:53 -0800 Subject: [PATCH 444/554] add some node transform specs --- spec/transform_spec.moon | 100 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 98 insertions(+), 2 deletions(-) diff --git a/spec/transform_spec.moon b/spec/transform_spec.moon index dba44d04..3952fdee 100644 --- a/spec/transform_spec.moon +++ b/spec/transform_spec.moon @@ -1,11 +1,107 @@ import with_dev from require "spec.helpers" + describe "moonscript.transform.destructure", -> - local extract_assign_names + local extract_assign_names, split_assign, Block with_dev -> - { :extract_assign_names } = require "moonscript.transform.destructure" + { :extract_assign_names, :split_assign } = require "moonscript.transform.destructure" + {:Block} = require "moonscript.compile" + + describe "split_assign #fff", -> + -- {:hello} = world + it "simple assignment", -> + node = { + "assign" + { + { "table", { + {{"key_literal", "hello"}, {"ref", "hello"}} + } + } + } + { + {"ref", "world"} + } + } + + out = split_assign Block!, node + + assert.same { + "group", { + { + "group", { + { "declare", { {"ref", "hello"} } } + { "assign", { {"ref", "hello"} }, { {"chain", {"ref", "world"}, {"dot", "hello"}} } } + } + } + } + }, out + + -- a, {:hello} = one, two + it "multiple assigns", -> + node = { + "assign" + { + {"ref", "a"} + { "table", { + {{"key_literal", "hello"}, {"ref", "hello"}} + } + } + } + { + {"ref", "one"} + {"ref", "two"} + } + } + + out = split_assign Block!, node + + assert.same { + "group", { + {"assign", { {"ref", "a"} }, { {"ref", "one"} }} + + { + "group", { + { "declare", { {"ref", "hello"} } } + { "assign", { {"ref", "hello"} }, { {"chain", {"ref", "two"}, {"dot", "hello"}} } } + } + } + } + }, out + + -- {:hello}, a = one, two + it "multiple assigns swapped #ddd", -> + node = { + "assign" + { + { "table", { + {{"key_literal", "hello"}, {"ref", "hello"}} + } + } + {"ref", "a"} + } + { + {"ref", "one"} + {"ref", "two"} + } + } + + out = split_assign Block!, node + + assert.same { + "group", { + { + "group", { + { "declare", { {"ref", "hello"} } } + { "assign", { {"ref", "hello"} }, { {"chain", {"ref", "one"}, {"dot", "hello"}} } } + } + } + + {"assign", { {"ref", "a"} }, { {"ref", "two"} }} + } + }, out + it "extracts names from table destructure", -> des = { From ce3a3f8bd98144477e4dd1d0601211f29d923138 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 22 Nov 2020 17:56:09 -0800 Subject: [PATCH 445/554] fetch binary deps --- .github/workflows/windows_exe.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/windows_exe.yml b/.github/workflows/windows_exe.yml index e170ebf1..97579be5 100644 --- a/.github/workflows/windows_exe.yml +++ b/.github/workflows/windows_exe.yml @@ -23,6 +23,16 @@ jobs: tar -xZf lua-5.1.5.tar.gz cd lua-5.1.5; make PLAT=mingw + - name: Get LPeg + run: | + curl -o lpeg.tar.gz http://www.inf.puc-rio.br/~roberto/lpeg/lpeg-1.0.2.tar.gz + tar -xZf lpeg.tar.gz + + - name: Get Luafilesystem + run: | + curl -o luafilesystem.tar.gz https://github.com/keplerproject/luafilesystem/archive/v1_8_0.tar.gz + tar -xZf luafilesystem.tar.gz + - name: List Files run: Get-ChildItem -Recurse From 13735f711da77f99b719606e88a731b12dde4f7a Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 22 Nov 2020 18:04:33 -0800 Subject: [PATCH 446/554] reformat things, add complex value temporary storage spec --- spec/transform_spec.moon | 81 +++++++++++++++++++++++++--------------- 1 file changed, 51 insertions(+), 30 deletions(-) diff --git a/spec/transform_spec.moon b/spec/transform_spec.moon index 3952fdee..9bb06a92 100644 --- a/spec/transform_spec.moon +++ b/spec/transform_spec.moon @@ -27,16 +27,45 @@ describe "moonscript.transform.destructure", -> out = split_assign Block!, node - assert.same { - "group", { - { - "group", { - { "declare", { {"ref", "hello"} } } - { "assign", { {"ref", "hello"} }, { {"chain", {"ref", "world"}, {"dot", "hello"}} } } + assert.same { "group", { + { "group", { + { "declare", { {"ref", "hello"} } } + { "assign", { {"ref", "hello"} }, { {"chain", {"ref", "world"}, {"dot", "hello"}} } } + }} + }}, out + + -- {:a, :b} = world! + -- a complex value should never be repeated to avoid double execution + it "complex value", -> + node = { + "assign" + { + { "table", { + {{"key_literal", "a"}, {"ref", "a"}} + {{"key_literal", "b"}, {"ref", "b"}} } } } - }, out + { + {"chain", {"ref", "world"}, {"call", {}}} + } + } + + out = split_assign Block!, node + + -- the temp name the result is stored into + tmp = {"temp_name", prefix: "obj"} + + assert.same { "group", { + { "group", { + { "declare", { {"ref", "a"}, {"ref", "b"} } } + + { "do", { + {"assign", { tmp }, { {"chain", {"ref", "world"}, {"call", {}}} } } + {"assign", { {"ref", "a"}, {"ref", "b"} }, { {"chain", tmp, {"dot", "a"}}, {"chain", tmp, {"dot", "b"}} } } + }} + }} + }}, out -- a, {:hello} = one, two it "multiple assigns", -> @@ -57,21 +86,17 @@ describe "moonscript.transform.destructure", -> out = split_assign Block!, node - assert.same { - "group", { - {"assign", { {"ref", "a"} }, { {"ref", "one"} }} + assert.same { "group", { + {"assign", { {"ref", "a"} }, { {"ref", "one"} }} - { - "group", { - { "declare", { {"ref", "hello"} } } - { "assign", { {"ref", "hello"} }, { {"chain", {"ref", "two"}, {"dot", "hello"}} } } - } - } - } - }, out + { "group", { + { "declare", { {"ref", "hello"} } } + { "assign", { {"ref", "hello"} }, { {"chain", {"ref", "two"}, {"dot", "hello"}} } } + }} + }}, out -- {:hello}, a = one, two - it "multiple assigns swapped #ddd", -> + it "multiple assigns swapped", -> node = { "assign" { @@ -89,18 +114,14 @@ describe "moonscript.transform.destructure", -> out = split_assign Block!, node - assert.same { - "group", { - { - "group", { - { "declare", { {"ref", "hello"} } } - { "assign", { {"ref", "hello"} }, { {"chain", {"ref", "one"}, {"dot", "hello"}} } } - } - } + assert.same { "group", { + { "group", { + { "declare", { {"ref", "hello"} } } + { "assign", { {"ref", "hello"} }, { {"chain", {"ref", "one"}, {"dot", "hello"}} } } + }} - {"assign", { {"ref", "a"} }, { {"ref", "two"} }} - } - }, out + {"assign", { {"ref", "a"} }, { {"ref", "two"} }} + }}, out it "extracts names from table destructure", -> From e2a44b040cc33e2d4f2d259aa16dac316b281bfc Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 22 Nov 2020 18:10:09 -0800 Subject: [PATCH 447/554] follow redirect --- .github/workflows/windows_exe.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/windows_exe.yml b/.github/workflows/windows_exe.yml index 97579be5..6b7ef1be 100644 --- a/.github/workflows/windows_exe.yml +++ b/.github/workflows/windows_exe.yml @@ -30,7 +30,7 @@ jobs: - name: Get Luafilesystem run: | - curl -o luafilesystem.tar.gz https://github.com/keplerproject/luafilesystem/archive/v1_8_0.tar.gz + curl -L -o luafilesystem.tar.gz https://github.com/keplerproject/luafilesystem/archive/v1_8_0.tar.gz tar -xZf luafilesystem.tar.gz - name: List Files From 21226eb5e291fad1b28b1605bb63892cd96fc8e3 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 22 Nov 2020 18:22:22 -0800 Subject: [PATCH 448/554] add compiler error when building invalid descructure --- moonscript/transform/destructure.lua | 1 + moonscript/transform/destructure.moon | 2 ++ 2 files changed, 3 insertions(+) diff --git a/moonscript/transform/destructure.lua b/moonscript/transform/destructure.lua index 2ec46bef..1e370b7d 100644 --- a/moonscript/transform/destructure.lua +++ b/moonscript/transform/destructure.lua @@ -103,6 +103,7 @@ extract_assign_names = function(name, accum, prefix) end local build_assign build_assign = function(scope, destruct_literal, receiver) + assert(receiver, "attempting to build destructure assign with no receiver") local extracted_names = extract_assign_names(destruct_literal) local names = { } local values = { } diff --git a/moonscript/transform/destructure.moon b/moonscript/transform/destructure.moon index 5b22247a..b0413b2d 100644 --- a/moonscript/transform/destructure.moon +++ b/moonscript/transform/destructure.moon @@ -54,6 +54,8 @@ extract_assign_names = (name, accum={}, prefix={}) -> accum build_assign = (scope, destruct_literal, receiver) -> + assert receiver, "attempting to build destructure assign with no receiver" + extracted_names = extract_assign_names destruct_literal names = {} From ef0e0f6ad2446e5eba8d816ef1e495f9541774e4 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 22 Nov 2020 18:26:59 -0800 Subject: [PATCH 449/554] build a c file --- .github/workflows/windows_exe.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/windows_exe.yml b/.github/workflows/windows_exe.yml index 6b7ef1be..fd0ee859 100644 --- a/.github/workflows/windows_exe.yml +++ b/.github/workflows/windows_exe.yml @@ -39,3 +39,7 @@ jobs: - name: Run Lua run: lua-5.1.5/src/lua.exe -v + - name: Build + run: gcc -o moon.exe -c bin/binaries/moon.c + + From d88e2e2dcf4f19805d905831f295d956ba83bcbb Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 22 Nov 2020 18:29:03 -0800 Subject: [PATCH 450/554] check in missing file :) --- bin/binaries/moon.c | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 bin/binaries/moon.c diff --git a/bin/binaries/moon.c b/bin/binaries/moon.c new file mode 100644 index 00000000..ea668ed9 --- /dev/null +++ b/bin/binaries/moon.c @@ -0,0 +1,4 @@ + +// this does nothing until we get a build working for all deps +int main(int argc, char **argv) { +} From 62c92ac2dca76b1b0437aaaabc1f623ceab728f4 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 22 Nov 2020 18:38:31 -0800 Subject: [PATCH 451/554] try building lpeg with bin --- .github/workflows/windows_exe.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/windows_exe.yml b/.github/workflows/windows_exe.yml index fd0ee859..f68c65bd 100644 --- a/.github/workflows/windows_exe.yml +++ b/.github/workflows/windows_exe.yml @@ -40,6 +40,8 @@ jobs: run: lua-5.1.5/src/lua.exe -v - name: Build - run: gcc -o moon.exe -c bin/binaries/moon.c + run: gcc -o moon.exe -ilua-5.1.5/src/ -c bin/binaries/moon.c lpeg-1.0.2/lpvm.c lpeg-1.0.2/lpcap.c lpeg-1.0.2/lptree.c lpeg-1.0.2/lpcode.c lpeg-1.0.2/lpprint.c + + From 36071113dff4ce265945e974223a06003a189c13 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 22 Nov 2020 18:41:23 -0800 Subject: [PATCH 452/554] quote arg? --- .github/workflows/windows_exe.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/windows_exe.yml b/.github/workflows/windows_exe.yml index f68c65bd..52d18cf5 100644 --- a/.github/workflows/windows_exe.yml +++ b/.github/workflows/windows_exe.yml @@ -40,7 +40,7 @@ jobs: run: lua-5.1.5/src/lua.exe -v - name: Build - run: gcc -o moon.exe -ilua-5.1.5/src/ -c bin/binaries/moon.c lpeg-1.0.2/lpvm.c lpeg-1.0.2/lpcap.c lpeg-1.0.2/lptree.c lpeg-1.0.2/lpcode.c lpeg-1.0.2/lpprint.c + run: gcc -o moon.exe '-ilua-5.1.5/src/' -c bin/binaries/moon.c lpeg-1.0.2/lpvm.c lpeg-1.0.2/lpcap.c lpeg-1.0.2/lptree.c lpeg-1.0.2/lpcode.c lpeg-1.0.2/lpprint.c From 03bdcf668a1a17b07414d64594363420f5419af0 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Mon, 23 Nov 2020 11:23:55 -0800 Subject: [PATCH 453/554] fix arg --- .github/workflows/windows_exe.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/windows_exe.yml b/.github/workflows/windows_exe.yml index 52d18cf5..9fdd7abc 100644 --- a/.github/workflows/windows_exe.yml +++ b/.github/workflows/windows_exe.yml @@ -40,7 +40,7 @@ jobs: run: lua-5.1.5/src/lua.exe -v - name: Build - run: gcc -o moon.exe '-ilua-5.1.5/src/' -c bin/binaries/moon.c lpeg-1.0.2/lpvm.c lpeg-1.0.2/lpcap.c lpeg-1.0.2/lptree.c lpeg-1.0.2/lpcode.c lpeg-1.0.2/lpprint.c + run: gcc -o moon.exe '-Ilua-5.1.5/src/' -c bin/binaries/moon.c lpeg-1.0.2/lpvm.c lpeg-1.0.2/lpcap.c lpeg-1.0.2/lptree.c lpeg-1.0.2/lpcode.c lpeg-1.0.2/lpprint.c From e445bb51e63a7b6dc369c157f4cba15ac0c5c1be Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Mon, 23 Nov 2020 11:41:33 -0800 Subject: [PATCH 454/554] remove extraneous arg --- .github/workflows/windows_exe.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/windows_exe.yml b/.github/workflows/windows_exe.yml index 9fdd7abc..fd23805d 100644 --- a/.github/workflows/windows_exe.yml +++ b/.github/workflows/windows_exe.yml @@ -40,7 +40,7 @@ jobs: run: lua-5.1.5/src/lua.exe -v - name: Build - run: gcc -o moon.exe '-Ilua-5.1.5/src/' -c bin/binaries/moon.c lpeg-1.0.2/lpvm.c lpeg-1.0.2/lpcap.c lpeg-1.0.2/lptree.c lpeg-1.0.2/lpcode.c lpeg-1.0.2/lpprint.c + run: gcc -o moon.exe '-Ilua-5.1.5/src/' bin/binaries/moon.c lpeg-1.0.2/lpvm.c lpeg-1.0.2/lpcap.c lpeg-1.0.2/lptree.c lpeg-1.0.2/lpcode.c lpeg-1.0.2/lpprint.c From 29d8ccc53f8c49f4cd166444bd8a0721487297d6 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 25 Nov 2020 14:46:25 -0800 Subject: [PATCH 455/554] run tests on pull request --- .github/workflows/spec.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/spec.yml b/.github/workflows/spec.yml index 7ddab019..91707d8c 100644 --- a/.github/workflows/spec.yml +++ b/.github/workflows/spec.yml @@ -1,6 +1,6 @@ name: "spec" -on: [push] +on: [push, pull_request] jobs: test: From ca9ccfe4301c4c78fbd4e737e952604e5fb810b1 Mon Sep 17 00:00:00 2001 From: codinget Date: Tue, 29 Dec 2020 17:09:33 +0100 Subject: [PATCH 456/554] Theoretically fix `-` flag for `moonc` `moonc` currently tells argparse to expect `-`, but actually checks for `--` on the cli, which breaks `moonc -`; this should in theory fix this --- bin/moonc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/moonc b/bin/moonc index 015979ad..e462d83b 100755 --- a/bin/moonc +++ b/bin/moonc @@ -20,7 +20,7 @@ parser:mutex( parser:flag("-", "Read from standard in, print to standard out (Must be only argument)") -local read_stdin = arg[1] == "--" -- luacheck: ignore 113 +local read_stdin = arg[1] == "-" -- luacheck: ignore 113 if not read_stdin then parser:argument("file/directory"):args("+") From f04ae47efbfdf0d2e92b60b6f5565a694d8c79a4 Mon Sep 17 00:00:00 2001 From: Codinget Date: Tue, 29 Dec 2020 17:14:52 +0100 Subject: [PATCH 457/554] fix moonc - --- bin/moonc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/moonc b/bin/moonc index e462d83b..98e8eda0 100755 --- a/bin/moonc +++ b/bin/moonc @@ -26,7 +26,7 @@ if not read_stdin then parser:argument("file/directory"):args("+") end -local opts = parser:parse() +local opts = read_stdin and {} or parser:parse() if opts.version then local v = require "moonscript.version" From 7de31c59d3c8509032b7fa2d611c03f74bd9c176 Mon Sep 17 00:00:00 2001 From: Codinget Date: Tue, 29 Dec 2020 17:16:44 +0100 Subject: [PATCH 458/554] force - to be the only argument --- bin/moonc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bin/moonc b/bin/moonc index 98e8eda0..0d8dd4a9 100755 --- a/bin/moonc +++ b/bin/moonc @@ -24,6 +24,11 @@ local read_stdin = arg[1] == "-" -- luacheck: ignore 113 if not read_stdin then parser:argument("file/directory"):args("+") +else + if arg[2] ~= nil then + io.stderr:write("- must be the only argument\n") + os.exit(1) + end end local opts = read_stdin and {} or parser:parse() From b7efcd131046ed921ae1075d7c0f6a3b64a570f7 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 18 Mar 2021 11:51:52 -0700 Subject: [PATCH 459/554] show class name when dumping in front of { --- moonscript/util.lua | 6 +++++- moonscript/util.moon | 5 ++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/moonscript/util.lua b/moonscript/util.lua index bde0d576..714767ed 100644 --- a/moonscript/util.lua +++ b/moonscript/util.lua @@ -102,7 +102,11 @@ dump = function(what) lines = _accum_0 end seen[what] = false - return "{\n" .. concat(lines) .. (" "):rep((depth - 1) * 4) .. "}\n" + local class_name + if what.__class then + class_name = "<" .. tostring(what.__class.__name) .. ">" + end + return tostring(class_name or "") .. "{\n" .. concat(lines) .. (" "):rep((depth - 1) * 4) .. "}\n" else return tostring(what) .. "\n" end diff --git a/moonscript/util.moon b/moonscript/util.moon index ea7c8a5b..9516c8bc 100644 --- a/moonscript/util.moon +++ b/moonscript/util.moon @@ -70,7 +70,10 @@ dump = (what) -> seen[what] = false - "{\n" .. concat(lines) .. (" ")\rep((depth - 1)*4) .. "}\n" + class_name = if what.__class + "<#{what.__class.__name}>" + + "#{class_name or ""}{\n" .. concat(lines) .. (" ")\rep((depth - 1)*4) .. "}\n" else tostring(what).."\n" From b3dfdc9cad86d09e7f13de79c8638a9525c163d6 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 2 Nov 2022 14:45:36 -0700 Subject: [PATCH 460/554] fix indentation in file --- bin/moonc | 323 +++++++++++++++++++++++++++--------------------------- 1 file changed, 163 insertions(+), 160 deletions(-) diff --git a/bin/moonc b/bin/moonc index 015979ad..09785d08 100755 --- a/bin/moonc +++ b/bin/moonc @@ -6,38 +6,41 @@ local lfs = require "lfs" local parser = argparse() parser:flag("-l --lint", "Perform a lint on the file instead of compiling") + parser:flag("-v --version", "Print version") parser:flag("-w --watch", "Watch file/directory for updates") parser:option("--transform", "Transform syntax tree with module") + parser:mutex( - parser:option("-t --output-to", "Specify where to place compiled files"), - parser:option("-o", "Write output to file"), - parser:flag("-p", "Write output to standard output"), - parser:flag("-T", "Write parse tree instead of code (to stdout)"), - parser:flag("-b", "Write parse and compile time instead of code(to stdout)"), - parser:flag("-X", "Write line rewrite map instead of code (to stdout)") + parser:option("-t --output-to", "Specify where to place compiled files"), + parser:option("-o", "Write output to file"), + parser:flag("-p", "Write output to standard output"), + parser:flag("-T", "Write parse tree instead of code (to stdout)"), + parser:flag("-b", "Write parse and compile time instead of code(to stdout)"), + parser:flag("-X", "Write line rewrite map instead of code (to stdout)") ) + parser:flag("-", - "Read from standard in, print to standard out (Must be only argument)") + "Read from standard in, print to standard out (Must be only argument)") local read_stdin = arg[1] == "--" -- luacheck: ignore 113 if not read_stdin then - parser:argument("file/directory"):args("+") + parser:argument("file/directory"):args("+") end local opts = parser:parse() if opts.version then - local v = require "moonscript.version" - v.print_version() - os.exit() + local v = require "moonscript.version" + v.print_version() + os.exit() end function log_msg(...) - if not opts.p then - io.stderr:write(table.concat({...}, " ") .. "\n") - end + if not opts.p then + io.stderr:write(table.concat({...}, " ") .. "\n") + end end local moonc = require("moonscript.cmd.moonc") @@ -47,186 +50,186 @@ local compile_and_write = moonc.compile_and_write local path_to_target = moonc.path_to_target local function scan_directory(root, collected) - root = normalize_dir(root) - collected = collected or {} - - for fname in lfs.dir(root) do - if not fname:match("^%.") then - local full_path = root..fname - - if lfs.attributes(full_path, "mode") == "directory" then - scan_directory(full_path, collected) - elseif fname:match("%.moon$") then - table.insert(collected, full_path) - end - end - end - - return collected + root = normalize_dir(root) + collected = collected or {} + + for fname in lfs.dir(root) do + if not fname:match("^%.") then + local full_path = root..fname + + if lfs.attributes(full_path, "mode") == "directory" then + scan_directory(full_path, collected) + elseif fname:match("%.moon$") then + table.insert(collected, full_path) + end + end + end + + return collected end local function remove_dups(tbl, key_fn) - local hash = {} - local final = {} - - for _, v in ipairs(tbl) do - local dup_key = key_fn and key_fn(v) or v - if not hash[dup_key] then - table.insert(final, v) - hash[dup_key] = true - end - end - - return final + local hash = {} + local final = {} + + for _, v in ipairs(tbl) do + local dup_key = key_fn and key_fn(v) or v + if not hash[dup_key] then + table.insert(final, v) + hash[dup_key] = true + end + end + + return final end -- creates tuples of input and target local function get_files(fname, files) - files = files or {} - - if lfs.attributes(fname, "mode") == "directory" then - for _, sub_fname in ipairs(scan_directory(fname)) do - table.insert(files, { - sub_fname, - path_to_target(sub_fname, opts.output_to, fname) - }) - end - else - table.insert(files, { - fname, - path_to_target(fname, opts.output_to) - }) - end - - return files + files = files or {} + + if lfs.attributes(fname, "mode") == "directory" then + for _, sub_fname in ipairs(scan_directory(fname)) do + table.insert(files, { + sub_fname, + path_to_target(sub_fname, opts.output_to, fname) + }) + end + else + table.insert(files, { + fname, + path_to_target(fname, opts.output_to) + }) + end + + return files end if read_stdin then - local parse = require "moonscript.parse" - local compile = require "moonscript.compile" + local parse = require "moonscript.parse" + local compile = require "moonscript.compile" - local text = io.stdin:read("*a") - local tree, err = parse.string(text) + local text = io.stdin:read("*a") + local tree, err = parse.string(text) - if not tree then error(err) end - local code, err, pos = compile.tree(tree) + if not tree then error(err) end + local code, err, pos = compile.tree(tree) - if not code then - error(compile.format_error(err, pos, text)) - end + if not code then + error(compile.format_error(err, pos, text)) + end - print(code) - os.exit() + print(code) + os.exit() end local inputs = opts["file/directory"] local files = {} for _, input in ipairs(inputs) do - get_files(input, files) + get_files(input, files) end files = remove_dups(files, function(f) - return f[2] + return f[2] end) -- returns an iterator that returns files that have been updated local function create_watcher(files) - local watchers = require("moonscript.cmd.watchers") + local watchers = require("moonscript.cmd.watchers") - if watchers.InotifyWacher:available() then - return watchers.InotifyWacher(files):each_update() - end + if watchers.InotifyWacher:available() then + return watchers.InotifyWacher(files):each_update() + end - return watchers.SleepWatcher(files):each_update() + return watchers.SleepWatcher(files):each_update() end if opts.watch then - -- build function to check for lint or compile in watch - local handle_file - if opts.lint then - local lint = require "moonscript.cmd.lint" - handle_file = lint.lint_file - else - handle_file = compile_and_write - end - - local watcher = create_watcher(files) - -- catches interrupt error for ctl-c - local protected = function() - local status, file = true, watcher() - if status then - return file - elseif file ~= "interrupted!" then - error(file) - end - end - - for fname in protected do - local target = path_to_target(fname, opts.t) - - if opts.o then - target = opts.o - end - - local success, err = handle_file(fname, target) - if opts.lint then - if success then - io.stderr:write(success .. "\n\n") - elseif err then - io.stderr:write(fname .. "\n" .. err .. "\n\n") - end - elseif not success then - io.stderr:write(table.concat({ - "", - "Error: " .. fname, - err, - "\n", - }, "\n")) - elseif success == "build" then - log_msg("Built", fname, "->", target) - end - end - - io.stderr:write("\nQuitting...\n") + -- build function to check for lint or compile in watch + local handle_file + if opts.lint then + local lint = require "moonscript.cmd.lint" + handle_file = lint.lint_file + else + handle_file = compile_and_write + end + + local watcher = create_watcher(files) + -- catches interrupt error for ctl-c + local protected = function() + local status, file = true, watcher() + if status then + return file + elseif file ~= "interrupted!" then + error(file) + end + end + + for fname in protected do + local target = path_to_target(fname, opts.t) + + if opts.o then + target = opts.o + end + + local success, err = handle_file(fname, target) + if opts.lint then + if success then + io.stderr:write(success .. "\n\n") + elseif err then + io.stderr:write(fname .. "\n" .. err .. "\n\n") + end + elseif not success then + io.stderr:write(table.concat({ + "", + "Error: " .. fname, + err, + "\n", + }, "\n")) + elseif success == "build" then + log_msg("Built", fname, "->", target) + end + end + + io.stderr:write("\nQuitting...\n") elseif opts.lint then - local has_linted_with_error; - local lint = require "moonscript.cmd.lint" - for _, tuple in pairs(files) do - local fname = tuple[1] - local res, err = lint.lint_file(fname) - if res then - has_linted_with_error = true - io.stderr:write(res .. "\n\n") - elseif err then - has_linted_with_error = true - io.stderr:write(fname .. "\n" .. err.. "\n\n") - end - end - if has_linted_with_error then - os.exit(1) - end + local has_linted_with_error; + local lint = require "moonscript.cmd.lint" + for _, tuple in pairs(files) do + local fname = tuple[1] + local res, err = lint.lint_file(fname) + if res then + has_linted_with_error = true + io.stderr:write(res .. "\n\n") + elseif err then + has_linted_with_error = true + io.stderr:write(fname .. "\n" .. err.. "\n\n") + end + end + if has_linted_with_error then + os.exit(1) + end else - for _, tuple in ipairs(files) do - local fname, target = util.unpack(tuple) - if opts.o then - target = opts.o - end - - local success, err = compile_and_write(fname, target, { - print = opts.p, - fname = fname, - benchmark = opts.b, - show_posmap = opts.X, - show_parse_tree = opts.T, - transform_module = opts.transform - }) - - if not success then - io.stderr:write(fname .. "\t" .. err .. "\n") - os.exit(1) - end - end + for _, tuple in ipairs(files) do + local fname, target = util.unpack(tuple) + if opts.o then + target = opts.o + end + + local success, err = compile_and_write(fname, target, { + print = opts.p, + fname = fname, + benchmark = opts.b, + show_posmap = opts.X, + show_parse_tree = opts.T, + transform_module = opts.transform + }) + + if not success then + io.stderr:write(fname .. "\t" .. err .. "\n") + os.exit(1) + end + end end From 87fa9e8da828594bf03f871fbdde31b8f6dcfb03 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 4 Nov 2022 12:49:30 -0700 Subject: [PATCH 461/554] clean up the makefile --- Makefile | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/Makefile b/Makefile index d1c2b1f7..5f29047f 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ LUA ?= lua5.1 LUA_VERSION = $(shell $(LUA) -e 'print(_VERSION:match("%d%.%d"))') -LUAROCKS = luarocks-$(LUA_VERSION) +LUAROCKS = luarocks --lua-version=$(LUA_VERSION) LUA_PATH_MAKE = $(shell $(LUAROCKS) path --lr-path);./?.lua;./?/init.lua LUA_CPATH_MAKE = $(shell $(LUAROCKS) path --lr-cpath);./?.so @@ -25,12 +25,6 @@ compile: $(LUA) bin/moonc -p bin/moon.moon >> bin/moon echo "-- vim: set filetype=lua:" >> bin/moon -compile_system: - moonc moon/ moonscript/ - echo "#!/usr/bin/env lua" > bin/moon - moonc -p bin/moon.moon >> bin/moon - echo "-- vim: set filetype=lua:" >> bin/moon - watch: moonc moon/ moonscript/ && moonc -w moon/ moonscript/ From 8bd7dc27b725faa3250ce572cab5b611bd2a398f Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 4 Nov 2022 13:04:11 -0700 Subject: [PATCH 462/554] more misc makefile changes --- Makefile | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index 5f29047f..0582488e 100644 --- a/Makefile +++ b/Makefile @@ -4,10 +4,13 @@ LUAROCKS = luarocks --lua-version=$(LUA_VERSION) LUA_PATH_MAKE = $(shell $(LUAROCKS) path --lr-path);./?.lua;./?/init.lua LUA_CPATH_MAKE = $(shell $(LUAROCKS) path --lr-cpath);./?.so -.PHONY: test local compile compile_system watch lint count show +.PHONY: test local build watch lint count show -test: - busted +build: + LUA_PATH='$(LUA_PATH_MAKE)' LUA_CPATH='$(LUA_CPATH_MAKE)' $(LUA) bin/moonc moon/ moonscript/ + echo "#!/usr/bin/env lua" > bin/moon + $(LUA) bin/moonc -p bin/moon.moon >> bin/moon + echo "-- vim: set filetype=lua:" >> bin/moon show: # LUA $(LUA) @@ -16,14 +19,11 @@ show: # LUA_PATH_MAKE $(LUA_PATH_MAKE) # LUA_CPATH_MAKE $(LUA_CPATH_MAKE) -local: compile - LUA_PATH='$(LUA_PATH_MAKE)' LUA_CPATH='$(LUA_CPATH_MAKE)' $(LUAROCKS) make --local moonscript-dev-1.rockspec +test: build + busted -compile: - LUA_PATH='$(LUA_PATH_MAKE)' LUA_CPATH='$(LUA_CPATH_MAKE)' $(LUA) bin/moonc moon/ moonscript/ - echo "#!/usr/bin/env lua" > bin/moon - $(LUA) bin/moonc -p bin/moon.moon >> bin/moon - echo "-- vim: set filetype=lua:" >> bin/moon +local: build + LUA_PATH='$(LUA_PATH_MAKE)' LUA_CPATH='$(LUA_CPATH_MAKE)' $(LUAROCKS) make --local moonscript-dev-1.rockspec watch: moonc moon/ moonscript/ && moonc -w moon/ moonscript/ From 0af9a8df8c283d643e5001ab665cf42dd26208a2 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 4 Nov 2022 13:06:37 -0700 Subject: [PATCH 463/554] bump up argparse dep --- moonscript-dev-1.rockspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/moonscript-dev-1.rockspec b/moonscript-dev-1.rockspec index 8970e306..b094bfaf 100644 --- a/moonscript-dev-1.rockspec +++ b/moonscript-dev-1.rockspec @@ -16,7 +16,7 @@ description = { dependencies = { "lua >= 5.1", "lpeg >= 0.10, ~= 0.11", - "argparse >= 0.5", + "argparse >= 0.7", "luafilesystem >= 1.5" } From 1ba34563f99e3e8a9d6685a0c84c3970a4885ede Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 4 Nov 2022 13:07:16 -0700 Subject: [PATCH 464/554] allow lua keyword property access on self #410 --- moonscript/cmd/lint.lua | 3 ++- moonscript/compile/value.lua | 38 +++++++++++++++++++++++++++++++++-- moonscript/compile/value.moon | 14 +++++++++++-- spec/inputs/syntax.moon | 3 +++ spec/outputs/syntax.lua | 2 ++ 5 files changed, 55 insertions(+), 5 deletions(-) diff --git a/moonscript/cmd/lint.lua b/moonscript/cmd/lint.lua index 8f036ff1..68053ca5 100644 --- a/moonscript/cmd/lint.lua +++ b/moonscript/cmd/lint.lua @@ -76,7 +76,8 @@ do _continue_0 = true break end - names_by_position[pos] = names_by_position[pos] or { } + local _update_0 = pos + names_by_position[_update_0] = names_by_position[_update_0] or { } insert(names_by_position[pos], name) _continue_0 = true until true diff --git a/moonscript/compile/value.lua b/moonscript/compile/value.lua index ce20dadd..913f9653 100644 --- a/moonscript/compile/value.lua +++ b/moonscript/compile/value.lua @@ -296,10 +296,44 @@ return { return self:line("not ", self:value(node[2])) end, self = function(self, node) - return "self." .. self:name(node[2]) + if data.lua_keywords[node[2]] then + return self:value({ + "chain", + "self", + { + "index", + { + "string", + '"', + node[2] + } + } + }) + else + return "self." .. self:name(node[2]) + end end, self_class = function(self, node) - return "self.__class." .. self:name(node[2]) + if data.lua_keywords[node[2]] then + return self:value({ + "chain", + "self", + { + "dot", + "__class" + }, + { + "index", + { + "string", + '"', + node[2] + } + } + }) + else + return "self.__class." .. self:name(node[2]) + end end, self_colon = function(self, node) return "self:" .. self:name(node[2]) diff --git a/moonscript/compile/value.moon b/moonscript/compile/value.moon index 7cfdda4e..0c07898d 100644 --- a/moonscript/compile/value.moon +++ b/moonscript/compile/value.moon @@ -183,10 +183,20 @@ string_chars = { @line "not ", @value node[2] self: (node) => - "self."..@name node[2] + if data.lua_keywords[node[2]] + @value {"chain", "self", {"index", { + "string", '"', node[2] + }}} + else + "self."..@name node[2] self_class: (node) => - "self.__class."..@name node[2] + if data.lua_keywords[node[2]] + @value {"chain", "self", {"dot", "__class"}, {"index", { + "string", '"', node[2] + }}} + else + "self.__class."..@name node[2] self_colon: (node) => "self:"..@name node[2] diff --git a/spec/inputs/syntax.moon b/spec/inputs/syntax.moon index 854f6297..b5b92a84 100644 --- a/spec/inputs/syntax.moon +++ b/spec/inputs/syntax.moon @@ -158,6 +158,9 @@ hello ..= "world" @@something += 10 @something += 10 +@@then += 10 +@then += 10 + a["hello"] += 10 a["hello#{tostring ff}"] += 10 a[four].x += 10 diff --git a/spec/outputs/syntax.lua b/spec/outputs/syntax.lua index 52c5d88f..8667f348 100644 --- a/spec/outputs/syntax.lua +++ b/spec/outputs/syntax.lua @@ -162,6 +162,8 @@ local m = m % 2 local hello = hello .. "world" self.__class.something = self.__class.something + 10 self.something = self.something + 10 +self.__class["then"] = self.__class["then"] + 10 +self["then"] = self["then"] + 10 local _update_0 = "hello" a[_update_0] = a[_update_0] + 10 local _update_1 = "hello" .. tostring(tostring(ff)) From 66cc505f94de2724f4d73a6c6faf86ae08a9b7c6 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 4 Nov 2022 13:12:10 -0700 Subject: [PATCH 465/554] minor makefile/spec tweaks --- Makefile | 4 ++++ spec/README.md | 10 ---------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index 0582488e..4df5d776 100644 --- a/Makefile +++ b/Makefile @@ -22,6 +22,10 @@ show: test: build busted + +build_test_outputs: build + BUILD=1 busted spec/lang_spec.moon + local: build LUA_PATH='$(LUA_PATH_MAKE)' LUA_CPATH='$(LUA_CPATH_MAKE)' $(LUAROCKS) make --local moonscript-dev-1.rockspec diff --git a/spec/README.md b/spec/README.md index 37699484..bdffb54e 100644 --- a/spec/README.md +++ b/spec/README.md @@ -44,13 +44,3 @@ describe "moonscript.base", -> `with_dev`'s require function will load the `.lua` files in the local directory, not the `moon` ones. You're responsible for compiling them first before running the tests. - -You might do - -```bash -$ make compile_system; busted -``` - -> `make compile_system` is a makefile task included in the repo that will build -> MoonScript in the current directory with the version installed to the system - From 75aa95d8f36154b68f051e9e664d77a95044f6b1 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 4 Nov 2022 13:22:28 -0700 Subject: [PATCH 466/554] update readme about building the syntax tests --- spec/README.md | 45 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/spec/README.md b/spec/README.md index bdffb54e..b5ba9594 100644 --- a/spec/README.md +++ b/spec/README.md @@ -1,6 +1,8 @@ # MoonScript spec guide +## Testing the right code + Because MoonScript is written in MoonScript, and MoonScript specs are written in MoonScript, you need to be aware of which copy of MoonScript is actually executing the specs. @@ -19,9 +21,14 @@ MoonScript available in the load path: When developing you want to make ensure the tests are executing your changes in the current directory, and not testing the system install. -Code running in Busted will have the system install take precedence over the -loaded version. That means that if you `require "moonscript.base"` for a test, -you won't get the local copy. +Busted itself is MoonScript aware, so it means it should have a functional +MoonScript compiler in order to load the `.moon` test files. This should be the +system install. After booting your specs though, you would like to use the +current directory version of MoonScript to the test + +Because by default Busted will have the system install take precedence over the +loaded version, running `require "moonscript.base"` within a test you won't get +the working directory version of the code that you should be testing. The `with_dev` spec helper will ensure that any require calls within the spec that ask for MoonScript modules. `with_dev` calls a setup and teardown that @@ -40,7 +47,33 @@ describe "moonscript.base", -> moonscript.load "print 12" ``` - -`with_dev`'s require function will load the `.lua` files in the local -directory, not the `moon` ones. You're responsible for compiling them first +Note that `with_dev`'s `require` function will not use the MoonLoader, it will +only load the `.lua` files in the working directory directory, not the `moon` +ones. This means you must compile the working directory version of MoonScript before running the tests. + +There is a make task to conveniently do all of this: + +``` +make test +``` + +## Building syntax tests + +The test suite has a series of *syntax* tests (`spec/lang_spec.moon`) that +consist of a bunch of `.moon` files and their expected output. These files +should capture a large range of syntax that can be verified to have the correct +output when you make changes to the language. + +If you are adding new syntax, or changing the expected output, then these tests +will fail until you rebuild the expected outputs. You can do this by running +the syntax test suite with the `BUILD` environment variable set. + +There is a make task to conveniently do this: + +``` +make build_test_outputs +``` + + + From 791e015bbea05038764c30ef46103546ba4dbb74 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 4 Nov 2022 13:22:43 -0700 Subject: [PATCH 467/554] bring back build from system --- Makefile | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 4df5d776..ed924438 100644 --- a/Makefile +++ b/Makefile @@ -12,6 +12,14 @@ build: $(LUA) bin/moonc -p bin/moon.moon >> bin/moon echo "-- vim: set filetype=lua:" >> bin/moon + +# This will rebuild MoonScript from the (hopefully working) system installation of moonc +build_from_system: + moonc moon/ moonscript/ + echo "#!/usr/bin/env lua" > bin/moon + moonc -p bin/moon.moon >> bin/moon + echo "-- vim: set filetype=lua:" >> bin/moon + show: # LUA $(LUA) # LUA_VERSION $(LUA_VERSION) @@ -22,7 +30,6 @@ show: test: build busted - build_test_outputs: build BUILD=1 busted spec/lang_spec.moon From c7be4dcb387af640aa226969486e556058361319 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 4 Nov 2022 13:25:24 -0700 Subject: [PATCH 468/554] use name here --- moonscript/compile/value.lua | 4 ++-- moonscript/compile/value.moon | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/moonscript/compile/value.lua b/moonscript/compile/value.lua index 913f9653..068035d0 100644 --- a/moonscript/compile/value.lua +++ b/moonscript/compile/value.lua @@ -305,7 +305,7 @@ return { { "string", '"', - node[2] + self:name(node[2]) } } }) @@ -327,7 +327,7 @@ return { { "string", '"', - node[2] + self:name(node[2]) } } }) diff --git a/moonscript/compile/value.moon b/moonscript/compile/value.moon index 0c07898d..677c08cc 100644 --- a/moonscript/compile/value.moon +++ b/moonscript/compile/value.moon @@ -185,7 +185,7 @@ string_chars = { self: (node) => if data.lua_keywords[node[2]] @value {"chain", "self", {"index", { - "string", '"', node[2] + "string", '"', @name node[2] }}} else "self."..@name node[2] @@ -193,7 +193,7 @@ string_chars = { self_class: (node) => if data.lua_keywords[node[2]] @value {"chain", "self", {"dot", "__class"}, {"index", { - "string", '"', node[2] + "string", '"', @name node[2] }}} else "self.__class."..@name node[2] From a1265cf7a11c137d8caa0eff89fddb46c24d9903 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 4 Nov 2022 13:29:46 -0700 Subject: [PATCH 469/554] misc cleanups --- moonscript/compile/value.lua | 18 ++++++++++-------- moonscript/compile/value.moon | 19 +++++++++++-------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/moonscript/compile/value.lua b/moonscript/compile/value.lua index 068035d0..ca6e5041 100644 --- a/moonscript/compile/value.lua +++ b/moonscript/compile/value.lua @@ -296,7 +296,8 @@ return { return self:line("not ", self:value(node[2])) end, self = function(self, node) - if data.lua_keywords[node[2]] then + local field_name = self:name(node[2]) + if data.lua_keywords[field_name] then return self:value({ "chain", "self", @@ -305,16 +306,17 @@ return { { "string", '"', - self:name(node[2]) + field_name } } }) else - return "self." .. self:name(node[2]) + return "self." .. tostring(field_name) end end, self_class = function(self, node) - if data.lua_keywords[node[2]] then + local field_name = self:name(node[2]) + if data.lua_keywords[field_name] then return self:value({ "chain", "self", @@ -327,19 +329,19 @@ return { { "string", '"', - self:name(node[2]) + field_name } } }) else - return "self.__class." .. self:name(node[2]) + return "self.__class." .. tostring(field_name) end end, self_colon = function(self, node) - return "self:" .. self:name(node[2]) + return "self:" .. tostring(self:name(node[2])) end, self_class_colon = function(self, node) - return "self.__class:" .. self:name(node[2]) + return "self.__class:" .. tostring(self:name(node[2])) end, ref = function(self, value) do diff --git a/moonscript/compile/value.moon b/moonscript/compile/value.moon index 677c08cc..1bfa754b 100644 --- a/moonscript/compile/value.moon +++ b/moonscript/compile/value.moon @@ -183,26 +183,29 @@ string_chars = { @line "not ", @value node[2] self: (node) => - if data.lua_keywords[node[2]] + field_name = @name node[2] + if data.lua_keywords[field_name] @value {"chain", "self", {"index", { - "string", '"', @name node[2] + "string", '"', field_name }}} else - "self."..@name node[2] + "self.#{field_name}" self_class: (node) => - if data.lua_keywords[node[2]] + field_name = @name node[2] + + if data.lua_keywords[field_name] @value {"chain", "self", {"dot", "__class"}, {"index", { - "string", '"', @name node[2] + "string", '"', field_name }}} else - "self.__class."..@name node[2] + "self.__class.#{field_name}" self_colon: (node) => - "self:"..@name node[2] + "self:#{@name node[2]}" self_class_colon: (node) => - "self.__class:"..@name node[2] + "self.__class:#{@name node[2]}" -- a variable reference ref: (value) => From a0108328373d5f3f1aefb98341aa895dd75a1b2a Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 4 Nov 2022 13:38:05 -0700 Subject: [PATCH 470/554] mention TIME mode in language spec --- spec/README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/spec/README.md b/spec/README.md index b5ba9594..3ca43503 100644 --- a/spec/README.md +++ b/spec/README.md @@ -75,5 +75,17 @@ There is a make task to conveniently do this: make build_test_outputs ``` +## Performance timing + +The syntax specs have performance timing collection built in. To get these +times run the test suite with the `TIME` environment variable set. + +``` +TIME=1 busted spec/lang_spec.moon +``` + +Any changes to the compiler should not introduce any substantial performance +decreases. + From 0259c835fe4a09a127d694b22d30d2357d5feb26 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 22 Mar 2023 15:40:31 -0700 Subject: [PATCH 471/554] add util script for generating header for binaries --- bin/util/file_to_header.lua | 42 +++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 bin/util/file_to_header.lua diff --git a/bin/util/file_to_header.lua b/bin/util/file_to_header.lua new file mode 100644 index 00000000..71378367 --- /dev/null +++ b/bin/util/file_to_header.lua @@ -0,0 +1,42 @@ +-- this script is used to convert a source input file into a C header to embed +-- that file as a string. Works the same as xxd -i + +local input = ... + +local function read_file(file_path) + local file = assert(io.open(file_path, "rb")) + local content = file:read("*a") + file:close() + return content +end + +local function generate_c_header(input_file) + local function byte_to_hex(byte) + return string.format("0x%02x", byte:byte()) + end + + local function sanitize_name(name) + return (name:gsub("[^%w_]", "_")) + end + + local data = read_file(input_file) + local name = sanitize_name(input_file) + local header = {} + + table.insert(header, string.format("unsigned char %s[] = {", name)) + for i = 1, #data do + if i % 16 == 1 then + table.insert(header, "\n ") + end + table.insert(header, byte_to_hex(data:sub(i, i))) + if i ~= #data then + table.insert(header, ", ") + end + end + table.insert(header, "\n};\n") + table.insert(header, string.format("unsigned int %s_len = %d;\n", name, #data)) + + return table.concat(header) +end + +print(generate_c_header(input)) From fd9d0eee6d0dc9f6dbcea579e92ced6e69072e32 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 22 Mar 2023 15:43:33 -0700 Subject: [PATCH 472/554] rewrite binaries script to to build for both windows & linux --- .../{windows_exe.yml => binaries.yml} | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) rename .github/workflows/{windows_exe.yml => binaries.yml} (55%) diff --git a/.github/workflows/windows_exe.yml b/.github/workflows/binaries.yml similarity index 55% rename from .github/workflows/windows_exe.yml rename to .github/workflows/binaries.yml index fd23805d..bbb07a0a 100644 --- a/.github/workflows/windows_exe.yml +++ b/.github/workflows/binaries.yml @@ -3,12 +3,40 @@ name: "windows_exe" on: [push] jobs: - build: - runs-on: windows-latest + linux: + runs-on: ubuntu-latest steps: - uses: actions/checkout@master + - name: Show GCC + run: gcc -v + + - name: Setup Lua + run: | + curl -O https://www.lua.org/ftp/lua-5.1.5.tar.gz + tar -xZf lua-5.1.5.tar.gz + cd lua-5.1.5; make PLAT=mingw + + - name: Get LPeg + run: | + curl -o lpeg.tar.gz http://www.inf.puc-rio.br/~roberto/lpeg/lpeg-1.0.2.tar.gz + tar -xZf lpeg.tar.gz + + - name: Get Luafilesystem + run: | + curl -L -o luafilesystem.tar.gz https://github.com/keplerproject/luafilesystem/archive/v1_8_0.tar.gz + tar -xZf luafilesystem.tar.gz + + - name: Build + run: gcc -o moon '-Ilua-5.1.5/src/' bin/binaries/moon.c lpeg-1.0.2/lpvm.c lpeg-1.0.2/lpcap.c lpeg-1.0.2/lptree.c lpeg-1.0.2/lpcode.c lpeg-1.0.2/lpprint.c + + + windows: + runs-on: windows-latest + + steps: + - uses: actions/checkout@master - uses: msys2/setup-msys2@v2 with: From 1affa0abf6f2764862ed4825c6c5253ad3793590 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 22 Mar 2023 15:44:15 -0700 Subject: [PATCH 473/554] rename action --- .github/workflows/binaries.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/binaries.yml b/.github/workflows/binaries.yml index bbb07a0a..01b7f707 100644 --- a/.github/workflows/binaries.yml +++ b/.github/workflows/binaries.yml @@ -1,4 +1,4 @@ -name: "windows_exe" +name: "binaries" on: [push] From fa104985a6edb0890495e93515bca017031bef87 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 22 Mar 2023 15:48:51 -0700 Subject: [PATCH 474/554] fix invalid platform type on linux build --- .github/workflows/binaries.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/binaries.yml b/.github/workflows/binaries.yml index 01b7f707..c4a70626 100644 --- a/.github/workflows/binaries.yml +++ b/.github/workflows/binaries.yml @@ -16,7 +16,7 @@ jobs: run: | curl -O https://www.lua.org/ftp/lua-5.1.5.tar.gz tar -xZf lua-5.1.5.tar.gz - cd lua-5.1.5; make PLAT=mingw + cd lua-5.1.5; make - name: Get LPeg run: | From 00397fd64b14ce85a4b5d0198bd702d6fb69dcb7 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 22 Jun 2023 15:33:50 -0700 Subject: [PATCH 475/554] add moon-tags script for generating tag file for moonscript classes --- bin/moon-tags | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100755 bin/moon-tags diff --git a/bin/moon-tags b/bin/moon-tags new file mode 100755 index 00000000..88c7e854 --- /dev/null +++ b/bin/moon-tags @@ -0,0 +1,123 @@ +#!/usr/bin/env moon + +HEADER = [[ +!_TAG_FILE_FORMAT 2 /extended format/ +!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/ +!_TAG_PROGRAM_AUTHOR leaf corcoran /leafot@gmail.com/ +!_TAG_PROGRAM_NAME MoonTags // +!_TAG_PROGRAM_URL https://github.com/leafo/moonscript /GitHub repository/ +!_TAG_PROGRAM_VERSION 0.0.1 // +]] + +-- see `ctags --list-kinds` for examples of kinds +-- see `ctags --list-fields` + +argparse = require "argparse" + +parser = argparse "moon-tags", "Generate ctags style tags file for MoonScript files" +parser\argument("files", "MoonScript files to generate tags for")\args "+" +parser\flag "--include-line", "Include line number field for each tag" + +args = parser\parse [v for _, v in ipairs _G.arg] + +TAGS = {} -- the final output of tags + +literals = require "moonscript.parse.literals" +import Indent from require "moonscript.parse.util" + +import P, S, C, Cc, Cg, Cb, Ct, Cs, V from require "lpeg" + +-- consome the rest of the file +until_end = (1 - literals.Stop)^0 +whitespace = S"\t " -- not including newline +ignore_line = Ct until_end -- tag it for empty line + +-- we have to do this double Ct to capture both the full line and the grouped captures +Line = (p) -> Ct C Ct Cg(Indent, "indent") * p +Type = (name) -> Cg Cc(name), "type" + +class_line = Line P"class" * whitespace^1 * Cg(literals.Name, "tag") * until_end * Type "class" +-- TODO: support lapis style routes +-- class_property = Line P("@")^-1 * Cg(literals.Name, "tag") * P":" * until_end * Type "property" + +method = P { P"=>" + P(1 - literals.Stop) * V(1) } +class_method = Line P("@")^-1 * Cg(literals.Name, "tag") * P":" * method * until_end * Type "method" + +parse_lines = Ct P { + (class_line + class_method + ignore_line) * (P(-1) + literals.Break * V(1)) +} + +escape_tagaddress = (line_text) -> + replacements = P([[\]]) / [[\\]] + P([[/]]) / [[\/]] + P("\t") / [[\t]] + P("\r") / [[\r]] + P("\n") / [[\n]] + Cs((replacements + 1)^0)\match line_text + +for fname in *args.files + file = assert io.open fname + contents = assert file\read "*a" + lines = assert parse_lines\match contents + + class_stack = {} + + push_class = (cls) -> + assert cls.type == "class", "not a class match" + -- remove classes that are longer in scope due to indentation + for i=#class_stack,1,-1 + top = class_stack[i] + + if cls.indent <= top.indent + table.remove class_stack, i + else + break + + table.insert class_stack, cls + + -- find the class this property is associated with based on change in indent + -- the expeted indent is written to `step` on the first proprety + find_class = (property) -> + for i=#class_stack,1,-1 + top = class_stack[i] + step = property.indent - top.indent + + if step > 0 + if top.step == nil + top.step = step + + if step == top.step + return top + + for line_no, line in ipairs lines + continue unless next line + + {line_text, properties} = line + + fields = {"language:moon"} + if args.include_line + table.insert fields, 1, "line:#{line_no}" + + switch properties.type + when "method" + if cls = find_class properties + table.insert fields, "class:#{cls.tag}" + + table.insert TAGS, { + properties.tag + fname + "/^#{escape_tagaddress line_text}$/;\"" + "f" + table.concat fields, " " + } + when "class" + push_class properties + + table.insert TAGS, { + properties.tag + fname + "/^#{escape_tagaddress line_text}$/;\"" + "c" + table.concat fields, " " + } + +print HEADER +tag_lines = [table.concat(t, "\t") for t in *TAGS] +table.sort tag_lines +print table.concat tag_lines, "\n" From 02222d3410b05476c1f376e0fdb1dde28e10d05e Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 22 Jun 2023 16:28:33 -0700 Subject: [PATCH 476/554] extract export list and top level function definitions --- bin/moon-tags | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/bin/moon-tags b/bin/moon-tags index 88c7e854..9d365da8 100755 --- a/bin/moon-tags +++ b/bin/moon-tags @@ -33,18 +33,30 @@ whitespace = S"\t " -- not including newline ignore_line = Ct until_end -- tag it for empty line -- we have to do this double Ct to capture both the full line and the grouped captures -Line = (p) -> Ct C Ct Cg(Indent, "indent") * p Type = (name) -> Cg Cc(name), "type" +Line = (type_name, p) -> Ct C Ct Cg(Indent, "indent") * p * Type type_name + +class_line = Line "class", P"class" * whitespace^1 * Cg(literals.Name, "tag") * until_end -class_line = Line P"class" * whitespace^1 * Cg(literals.Name, "tag") * until_end * Type "class" -- TODO: support lapis style routes -- class_property = Line P("@")^-1 * Cg(literals.Name, "tag") * P":" * until_end * Type "property" method = P { P"=>" + P(1 - literals.Stop) * V(1) } -class_method = Line P("@")^-1 * Cg(literals.Name, "tag") * P":" * method * until_end * Type "method" +func = P { P"->" + P"=>" + P(1 - literals.Stop) * V(1) } + +-- this matches end-of-file return table convention for module files to figure +-- out what names are exported +export_list = Ct P"{" * P { + P"}" + ((P":" * literals.Name) + (P(1) - P"}")) * V(1) +} + +eof_exports = P { export_list * S(" \t\r\n")^0 * P(-1) + P(1) * V(1) } + +class_method = Line("method", P("@")^-1 * Cg(literals.Name, "tag") * P":" * method) * until_end +function_def = Line("function", Cg(literals.Name, "tag") * whitespace^0 * P"=" * func) * until_end parse_lines = Ct P { - (class_line + class_method + ignore_line) * (P(-1) + literals.Break * V(1)) + (class_line + class_method + function_def + ignore_line) * (P(-1) + literals.Break * V(1)) } escape_tagaddress = (line_text) -> @@ -54,6 +66,8 @@ escape_tagaddress = (line_text) -> for fname in *args.files file = assert io.open fname contents = assert file\read "*a" + exports = {e, true for e in *eof_exports\match(contents) or {}} + lines = assert parse_lines\match contents class_stack = {} @@ -95,6 +109,17 @@ for fname in *args.files table.insert fields, 1, "line:#{line_no}" switch properties.type + when "function" + if exports[properties.tag] and properties.indent == 0 + table.insert TAGS, { + properties.tag + fname + -- note we don't use $ here + "/^#{escape_tagaddress line_text}$/;\"" + "f" + table.concat fields, " " + } + when "method" if cls = find_class properties table.insert fields, "class:#{cls.tag}" @@ -102,6 +127,7 @@ for fname in *args.files table.insert TAGS, { properties.tag fname + -- note we don't use $ here "/^#{escape_tagaddress line_text}$/;\"" "f" table.concat fields, " " From 524d64ffd386f619a32850552dd760df6c29acc5 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 22 Jun 2023 19:45:34 -0700 Subject: [PATCH 477/554] use prefix mach for tag address for fucntions, since they are truncated --- bin/moon-tags | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/moon-tags b/bin/moon-tags index 9d365da8..2452a01e 100755 --- a/bin/moon-tags +++ b/bin/moon-tags @@ -60,7 +60,7 @@ parse_lines = Ct P { } escape_tagaddress = (line_text) -> - replacements = P([[\]]) / [[\\]] + P([[/]]) / [[\/]] + P("\t") / [[\t]] + P("\r") / [[\r]] + P("\n") / [[\n]] + replacements = S([[\/.$^]]) / [[\%0]]+ P("\t") / [[\t]] + P("\r") / [[\r]] + P("\n") / [[\n]] Cs((replacements + 1)^0)\match line_text for fname in *args.files @@ -115,7 +115,7 @@ for fname in *args.files properties.tag fname -- note we don't use $ here - "/^#{escape_tagaddress line_text}$/;\"" + "/^#{escape_tagaddress line_text}/;\"" "f" table.concat fields, " " } @@ -128,7 +128,7 @@ for fname in *args.files properties.tag fname -- note we don't use $ here - "/^#{escape_tagaddress line_text}$/;\"" + "/^#{escape_tagaddress line_text}/;\"" "f" table.concat fields, " " } From fbd8ad48737651114a3d3a672b9f8f8b3a7022b7 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 23 Jun 2023 09:33:37 -0700 Subject: [PATCH 478/554] add support for detecting lapis routes --- bin/moon-tags | 61 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 54 insertions(+), 7 deletions(-) diff --git a/bin/moon-tags b/bin/moon-tags index 2452a01e..0008a727 100755 --- a/bin/moon-tags +++ b/bin/moon-tags @@ -17,13 +17,14 @@ argparse = require "argparse" parser = argparse "moon-tags", "Generate ctags style tags file for MoonScript files" parser\argument("files", "MoonScript files to generate tags for")\args "+" parser\flag "--include-line", "Include line number field for each tag" +parser\flag "--lapis", "Support extracting lapis routes" args = parser\parse [v for _, v in ipairs _G.arg] TAGS = {} -- the final output of tags literals = require "moonscript.parse.literals" -import Indent from require "moonscript.parse.util" +import Indent, simple_string from require "moonscript.parse.util" import P, S, C, Cc, Cg, Cb, Ct, Cs, V from require "lpeg" @@ -32,18 +33,20 @@ until_end = (1 - literals.Stop)^0 whitespace = S"\t " -- not including newline ignore_line = Ct until_end -- tag it for empty line +-- NOTE: we disable interpolation parsing since we don't have full grammar +SingleString = simple_string "'", false +DoubleString = simple_string '"', false +String = SingleString + DoubleString + -- we have to do this double Ct to capture both the full line and the grouped captures Type = (name) -> Cg Cc(name), "type" Line = (type_name, p) -> Ct C Ct Cg(Indent, "indent") * p * Type type_name -class_line = Line "class", P"class" * whitespace^1 * Cg(literals.Name, "tag") * until_end - --- TODO: support lapis style routes --- class_property = Line P("@")^-1 * Cg(literals.Name, "tag") * P":" * until_end * Type "property" - method = P { P"=>" + P(1 - literals.Stop) * V(1) } func = P { P"->" + P"=>" + P(1 - literals.Stop) * V(1) } +self_prefix = Cg(P("@") * Cc(true), "self") + -- this matches end-of-file return table convention for module files to figure -- out what names are exported export_list = Ct P"{" * P { @@ -52,17 +55,37 @@ export_list = Ct P"{" * P { eof_exports = P { export_list * S(" \t\r\n")^0 * P(-1) + P(1) * V(1) } +class_line = Line "class", P"class" * whitespace^1 * Cg(literals.Name, "tag") * until_end +class_property = Line "property", self_prefix^-1 * Cg(literals.Name, "tag") * P":" * whitespace^0 * Cg(String, "value")^0 * until_end class_method = Line("method", P("@")^-1 * Cg(literals.Name, "tag") * P":" * method) * until_end function_def = Line("function", Cg(literals.Name, "tag") * whitespace^0 * P"=" * func) * until_end +lapis_route = Line "lapis-route", P"[" * Cg(literals.Name, "tag") * P":" * whitespace^0 * Cg(String, "route") * whitespace^0 * P("]:") * until_end + +line_types = class_line + class_method + class_property + function_def + +if args.lapis + line_types += lapis_route parse_lines = Ct P { - (class_line + class_method + function_def + ignore_line) * (P(-1) + literals.Break * V(1)) + (line_types + ignore_line) * (P(-1) + literals.Break * V(1)) } escape_tagaddress = (line_text) -> replacements = S([[\/.$^]]) / [[\%0]]+ P("\t") / [[\t]] + P("\r") / [[\r]] + P("\n") / [[\n]] Cs((replacements + 1)^0)\match line_text +import types from require "tableshape" + +class_field = types.partial { + "self": true + tag: types.string\tag "name" + value: types.partial { + "string" + types.string + types.string\tag "value" -- TODO: will need to un-escape this + } +} + for fname in *args.files file = assert io.open fname contents = assert file\read "*a" @@ -109,6 +132,30 @@ for fname in *args.files table.insert fields, 1, "line:#{line_no}" switch properties.type + when "lapis-route" + if cls = find_class properties + prefix = if cls.fields + cls.fields.name + + table.insert TAGS, { + "#{prefix or ""}#{properties.tag}" + fname + "/^#{escape_tagaddress line_text}/;\"" + "f" + table.concat fields, " " + } + + when "property" + -- this is necessary to register the correct indent level for the class + cls = find_class properties + + -- record the fields into the class object so they can be referenced by + -- other tags. Note this is code-order dependent + if cls and args.lapis + if field = class_field properties + cls.fields or= {} + cls.fields[field.name] = field.value + when "function" if exports[properties.tag] and properties.indent == 0 table.insert TAGS, { From 65c7b152f05efd79c8d65fd6a3be2fb28b50ce52 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 18 Oct 2023 15:27:23 -0700 Subject: [PATCH 479/554] add --no-header option for moon-tags --- bin/moon-tags | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bin/moon-tags b/bin/moon-tags index 0008a727..51b74fa4 100755 --- a/bin/moon-tags +++ b/bin/moon-tags @@ -18,6 +18,7 @@ parser = argparse "moon-tags", "Generate ctags style tags file for MoonScript fi parser\argument("files", "MoonScript files to generate tags for")\args "+" parser\flag "--include-line", "Include line number field for each tag" parser\flag "--lapis", "Support extracting lapis routes" +parser\flag "--no-header", "Don't print the header" args = parser\parse [v for _, v in ipairs _G.arg] @@ -190,7 +191,9 @@ for fname in *args.files table.concat fields, " " } -print HEADER +unless args.no_header + print HEADER + tag_lines = [table.concat(t, "\t") for t in *TAGS] table.sort tag_lines print table.concat tag_lines, "\n" From d5341c9093c49d3724072b209cde28b5cb0f47c9 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Mon, 6 Nov 2023 12:54:51 -0800 Subject: [PATCH 480/554] support "string" route names for lapis route detection in moon-tags --- bin/moon-tags | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bin/moon-tags b/bin/moon-tags index 51b74fa4..5f657d55 100755 --- a/bin/moon-tags +++ b/bin/moon-tags @@ -56,11 +56,14 @@ export_list = Ct P"{" * P { eof_exports = P { export_list * S(" \t\r\n")^0 * P(-1) + P(1) * V(1) } +-- convert a parsed string to the value the string represents +StringVal = C(String) / (str) -> loadstring("return " .. str)() + class_line = Line "class", P"class" * whitespace^1 * Cg(literals.Name, "tag") * until_end class_property = Line "property", self_prefix^-1 * Cg(literals.Name, "tag") * P":" * whitespace^0 * Cg(String, "value")^0 * until_end class_method = Line("method", P("@")^-1 * Cg(literals.Name, "tag") * P":" * method) * until_end function_def = Line("function", Cg(literals.Name, "tag") * whitespace^0 * P"=" * func) * until_end -lapis_route = Line "lapis-route", P"[" * Cg(literals.Name, "tag") * P":" * whitespace^0 * Cg(String, "route") * whitespace^0 * P("]:") * until_end +lapis_route = Line "lapis-route", P"[" * Cg(literals.Name + StringVal, "tag") * P":" * whitespace^0 * Cg(String, "route") * whitespace^0 * P("]:") * until_end line_types = class_line + class_method + class_property + function_def From 60094ca0be870462678925413b6528ae5bf4690a Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 23 Nov 2024 12:13:21 -0800 Subject: [PATCH 481/554] remove alt_getopt from splat --- bin/splat.moon | 36 +++++++++++++----------------------- 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/bin/splat.moon b/bin/splat.moon index df523c14..15c1a5a8 100755 --- a/bin/splat.moon +++ b/bin/splat.moon @@ -1,26 +1,18 @@ #!/usr/bin/env moon +argparse = require "argparse" --- concatenate a collection of lua modules into one +parser = argparse "splat.moon", "Concatenate a collection of Lua modules into a single file" +parser\option("--load -l", "Module names that will be load on require")\count "*" -lfs = require "lfs" -alt_getopt = require "alt_getopt" - -import insert, concat from table -import dump, split from require "moonscript.util" - -opts, ind = alt_getopt.get_opts arg, "l:", { - load: "l" -} +parser\argument("directories", "Directories to scan for Lua modules")\args "+" -if not arg[ind] - print "usage: splat [-l module_names] directory [directories...]" - os.exit! - -dirs = [a for a in *arg[ind,]] +args = parser\parse [v for _, v in ipairs _G.arg] +dirs = args.directories normalize = (path) -> path\match("(.-)/*$").."/" +lfs = require "lfs" scan_directory = (root, patt, collected={}) -> root = normalize root for fname in lfs.dir root @@ -31,7 +23,7 @@ scan_directory = (root, patt, collected={}) -> scan_directory full_path, patt, collected else if full_path\match patt - insert collected, full_path + table.insert collected, full_path collected @@ -39,15 +31,14 @@ path_to_module_name = (path) -> (path\match("(.-)%.lua")\gsub("/", ".")) each_line = (text) -> - import yield from coroutine coroutine.wrap -> start = 1 while true pos, after = text\find "\n", start, true break if not pos - yield text\sub start, pos - 1 + coroutine.yield text\sub start, pos - 1 start = after + 1 - yield text\sub start, #text + coroutine.yield text\sub start, #text nil write_module = (name, text) -> @@ -73,8 +64,7 @@ for dir in *dirs name = base write_module name, content -if opts.l - for module_name in *split opts.l, "," - if modules[module_name] - print ([[package.preload["%s"]()]])\format module_name +for module_name in *args.load + if modules[module_name] + print ([[package.preload["%s"]()]])\format module_name From 3db3ec8234a1d77ad6f1fd773057efddfdc79a77 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 1 Dec 2024 09:27:02 -0800 Subject: [PATCH 482/554] don't fail if object doesn't match class types strictly --- moonscript/util.lua | 2 +- moonscript/util.moon | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/moonscript/util.lua b/moonscript/util.lua index 714767ed..83d7e37f 100644 --- a/moonscript/util.lua +++ b/moonscript/util.lua @@ -103,7 +103,7 @@ dump = function(what) end seen[what] = false local class_name - if what.__class then + if type(what.__class) == "table" and type(what.__class.__name) == "string" then class_name = "<" .. tostring(what.__class.__name) .. ">" end return tostring(class_name or "") .. "{\n" .. concat(lines) .. (" "):rep((depth - 1) * 4) .. "}\n" diff --git a/moonscript/util.moon b/moonscript/util.moon index 9516c8bc..9969ac4a 100644 --- a/moonscript/util.moon +++ b/moonscript/util.moon @@ -70,7 +70,7 @@ dump = (what) -> seen[what] = false - class_name = if what.__class + class_name = if type(what.__class) == "table" and type(what.__class.__name) == "string" "<#{what.__class.__name}>" "#{class_name or ""}{\n" .. concat(lines) .. (" ")\rep((depth - 1)*4) .. "}\n" From 98448bdcb219d6df081e7986200784b83ccd10f3 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Tue, 14 Jan 2025 11:56:36 -0800 Subject: [PATCH 483/554] make moon.p print all arguments after dumping them --- moon/init.lua | 7 +++++-- moon/init.moon | 6 ++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/moon/init.lua b/moon/init.lua index d4c24903..52ead55d 100644 --- a/moon/init.lua +++ b/moon/init.lua @@ -8,8 +8,11 @@ do getfenv, setfenv, dump = _obj_0.getfenv, _obj_0.setfenv, _obj_0.dump end local p, is_object, type, debug, run_with_scope, bind_methods, defaultbl, extend, copy, mixin, mixin_object, mixin_table, fold -p = function(...) - return print(dump(...)) +p = function(o, ...) + print(dump(o)) + if select("#", ...) > 0 then + return p(...) + end end is_object = function(value) return lua.type(value) == "table" and value.__class diff --git a/moon/init.moon b/moon/init.moon index 658d8867..57325eea 100644 --- a/moon/init.moon +++ b/moon/init.moon @@ -4,8 +4,10 @@ import getfenv, setfenv, dump from require "moonscript.util" local * -p = (...) -> - print dump ... +p = (o, ...) -> + print dump o + if select("#", ...) > 0 + p ... is_object = (value) -> -- is a moonscript object lua.type(value) == "table" and value.__class From 3b134e01ebc5961ca132bff5ba2871c88d65347e Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 27 Feb 2025 11:30:46 -0800 Subject: [PATCH 484/554] misc readme update --- README.md | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 967b84f6..b5bb5f92 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,22 @@ Online demo/compiler at . ## Join Our Community -We just created a Discord for those interested in MoonScript. You can join us here: +We have a Discord for those interested in MoonScript and related projects. You can join us here: + +## Contributing + +MoonScript is a self-hosted compiler, meaning it's written in MoonScript itself. When contributing, please follow the following guidelines: + +1. Edit `.moon` files, never modify the alongside `.lua` files directly +2. After making changes to `.moon` files, run the compiler to regenerate the corresponding `.lua` files +3. Both `.moon` and `.lua` files are included in the repository to ensure that: + - Users can install and use MoonScript without having to compile it themselves + - The compiler bootstrapping process works consistently + +It's helpful to have a separate installation of MoonScript should you break +something and you need to re-build the MoonScript with a working version of +MoonScript. You can check out the repo in another directory, or install it +using LuaRocks to have a separate working version. ## Running Tests @@ -34,7 +49,6 @@ busted Writing specs is a bit more complicated. Check out [the spec writing guide](spec/README.md). - ## Binaries Precompiled versions of MoonScript are provided for Windows. You can find them @@ -53,7 +67,7 @@ branch](https://github.com/leafo/moonscript/tree/binaries) ## License (MIT) -Copyright (C) 2020 by Leaf Corcoran +Copyright (C) 2025 by Leaf Corcoran Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From b9768c893bd25c514c6404767fadec29dfd01060 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 17 Dec 2025 12:24:34 -0800 Subject: [PATCH 485/554] add support for `moon -e` to run code from command line --- bin/moon | 69 +++++++++++++++++++++++++++++++++++---------------- bin/moon.moon | 65 +++++++++++++++++++++++++++++++++--------------- 2 files changed, 93 insertions(+), 41 deletions(-) diff --git a/bin/moon b/bin/moon index 75f2156d..759cae8a 100755 --- a/bin/moon +++ b/bin/moon @@ -7,11 +7,12 @@ local unpack = util.unpack local argparser = argparse()({ name = "moon" }) -argparser:argument("script") +argparser:argument("script"):args("?") argparser:argument("args"):args("*") -argparser:option("-c --coverage", "Collect and print code coverage") -argparser:option("-d", "Disable stack trace rewriting") -argparser:option("-v --version", "Print version information") +argparser:flag("--coverage -c", "Collect and print code coverage") +argparser:flag("-d", "Disable stack trace rewriting") +argparser:option("--execute -e", "Execute MoonScript code string") +argparser:flag("--version -v", "Print version information") local base = 0 local _list_0 = arg for _index_0 = 1, #_list_0 do @@ -48,29 +49,55 @@ run = function() require("moonscript.version").print_version() os.exit() end - local script_fname = opts.script args = { unpack(arg, base + 1) } args[-1] = arg[0] - args[0] = opts.script local moonscript_chunk, lua_parse_error - local passed, err = pcall(function() - moonscript_chunk, lua_parse_error = moonscript.loadfile(script_fname, { - implicitly_return_root = false - }) - end) - if not (passed) then - print_err(err) - os.exit(1) - end - if not (moonscript_chunk) then - if lua_parse_error then - print_err(lua_parse_error) - else - print_err("Can't file file: " .. tostring(script_fname)) + if opts.execute then + args[0] = "-e" + local passed, err = pcall(function() + moonscript_chunk, lua_parse_error = moonscript.loadstring(opts.execute, "=(command line)", { + implicitly_return_root = false + }) + end) + if not (passed) then + print_err(err) + os.exit(1) + end + if not (moonscript_chunk) then + if lua_parse_error then + print_err(lua_parse_error) + else + print_err("Failed to compile: " .. tostring(opts.execute)) + end + os.exit(1) + end + else + local script_fname = opts.script + if not (script_fname) then + print_err("Usage: moon [options] script [args]") + print_err("Use 'moon --help' for more information.") + os.exit(1) + end + args[0] = script_fname + local passed, err = pcall(function() + moonscript_chunk, lua_parse_error = moonscript.loadfile(script_fname, { + implicitly_return_root = false + }) + end) + if not (passed) then + print_err(err) + os.exit(1) + end + if not (moonscript_chunk) then + if lua_parse_error then + print_err(lua_parse_error) + else + print_err("Can't file file: " .. tostring(script_fname)) + end + os.exit(1) end - os.exit(1) end util.getfenv(moonscript_chunk).arg = args local run_chunk diff --git a/bin/moon.moon b/bin/moon.moon index 94601d57..fcb8de89 100644 --- a/bin/moon.moon +++ b/bin/moon.moon @@ -8,11 +8,12 @@ unpack = util.unpack argparser = argparse! name: "moon" -argparser\argument "script" +argparser\argument("script")\args "?" argparser\argument("args")\args "*" -argparser\option "-c --coverage", "Collect and print code coverage" -argparser\option "-d", "Disable stack trace rewriting" -argparser\option "-v --version", "Print version information" +argparser\flag "--coverage -c", "Collect and print code coverage" +argparser\flag "-d", "Disable stack trace rewriting" +argparser\option "--execute -e", "Execute MoonScript code string" +argparser\flag "--version -v", "Print version information" base = 0 for flag in *arg @@ -31,30 +32,54 @@ run = -> require("moonscript.version").print_version! os.exit! - script_fname = opts.script - args = {unpack arg, base + 1} args[-1] = arg[0] - args[0] = opts.script local moonscript_chunk, lua_parse_error - passed, err = pcall -> - moonscript_chunk, lua_parse_error = moonscript.loadfile script_fname, { - implicitly_return_root: false - } + if opts.execute + args[0] = "-e" - unless passed - print_err err - os.exit 1 + passed, err = pcall -> + moonscript_chunk, lua_parse_error = moonscript.loadstring opts.execute, "=(command line)", { + implicitly_return_root: false + } - unless moonscript_chunk - if lua_parse_error - print_err lua_parse_error - else - print_err "Can't file file: #{script_fname}" + unless passed + print_err err + os.exit 1 - os.exit 1 + unless moonscript_chunk + if lua_parse_error + print_err lua_parse_error + else + print_err "Failed to compile: #{opts.execute}" + os.exit 1 + else + script_fname = opts.script + + unless script_fname + print_err "Usage: moon [options] script [args]" + print_err "Use 'moon --help' for more information." + os.exit 1 + + args[0] = script_fname + + passed, err = pcall -> + moonscript_chunk, lua_parse_error = moonscript.loadfile script_fname, { + implicitly_return_root: false + } + + unless passed + print_err err + os.exit 1 + + unless moonscript_chunk + if lua_parse_error + print_err lua_parse_error + else + print_err "Can't file file: #{script_fname}" + os.exit 1 util.getfenv(moonscript_chunk).arg = args From 6146357792ad823db40a84cc954423bcceef4554 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 8 Jan 2026 12:47:34 -0800 Subject: [PATCH 486/554] does this fix anything --- .github/workflows/binaries.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/binaries.yml b/.github/workflows/binaries.yml index c4a70626..3fc235e0 100644 --- a/.github/workflows/binaries.yml +++ b/.github/workflows/binaries.yml @@ -15,18 +15,18 @@ jobs: - name: Setup Lua run: | curl -O https://www.lua.org/ftp/lua-5.1.5.tar.gz - tar -xZf lua-5.1.5.tar.gz + tar -xzf lua-5.1.5.tar.gz cd lua-5.1.5; make - name: Get LPeg run: | curl -o lpeg.tar.gz http://www.inf.puc-rio.br/~roberto/lpeg/lpeg-1.0.2.tar.gz - tar -xZf lpeg.tar.gz + tar -xzf lpeg.tar.gz - name: Get Luafilesystem run: | curl -L -o luafilesystem.tar.gz https://github.com/keplerproject/luafilesystem/archive/v1_8_0.tar.gz - tar -xZf luafilesystem.tar.gz + tar -xzf luafilesystem.tar.gz - name: Build run: gcc -o moon '-Ilua-5.1.5/src/' bin/binaries/moon.c lpeg-1.0.2/lpvm.c lpeg-1.0.2/lpcap.c lpeg-1.0.2/lptree.c lpeg-1.0.2/lpcode.c lpeg-1.0.2/lpprint.c @@ -48,18 +48,18 @@ jobs: - name: Setup Lua run: | curl -O https://www.lua.org/ftp/lua-5.1.5.tar.gz - tar -xZf lua-5.1.5.tar.gz + tar -xzf lua-5.1.5.tar.gz cd lua-5.1.5; make PLAT=mingw - name: Get LPeg run: | curl -o lpeg.tar.gz http://www.inf.puc-rio.br/~roberto/lpeg/lpeg-1.0.2.tar.gz - tar -xZf lpeg.tar.gz + tar -xzf lpeg.tar.gz - name: Get Luafilesystem run: | curl -L -o luafilesystem.tar.gz https://github.com/keplerproject/luafilesystem/archive/v1_8_0.tar.gz - tar -xZf luafilesystem.tar.gz + tar -xzf luafilesystem.tar.gz - name: List Files run: Get-ChildItem -Recurse From 2e2e478345b2d9c87f0afbe3367ff970a3de63c1 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 8 Jan 2026 12:50:47 -0800 Subject: [PATCH 487/554] fix the curl commands --- .github/workflows/binaries.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/binaries.yml b/.github/workflows/binaries.yml index 3fc235e0..d916fe34 100644 --- a/.github/workflows/binaries.yml +++ b/.github/workflows/binaries.yml @@ -14,13 +14,13 @@ jobs: - name: Setup Lua run: | - curl -O https://www.lua.org/ftp/lua-5.1.5.tar.gz + curl -L -O https://www.lua.org/ftp/lua-5.1.5.tar.gz tar -xzf lua-5.1.5.tar.gz cd lua-5.1.5; make - name: Get LPeg run: | - curl -o lpeg.tar.gz http://www.inf.puc-rio.br/~roberto/lpeg/lpeg-1.0.2.tar.gz + curl -L -o lpeg.tar.gz https://www.inf.puc-rio.br/~roberto/lpeg/lpeg-1.0.2.tar.gz tar -xzf lpeg.tar.gz - name: Get Luafilesystem @@ -47,13 +47,13 @@ jobs: - name: Setup Lua run: | - curl -O https://www.lua.org/ftp/lua-5.1.5.tar.gz + curl -L -O https://www.lua.org/ftp/lua-5.1.5.tar.gz tar -xzf lua-5.1.5.tar.gz cd lua-5.1.5; make PLAT=mingw - name: Get LPeg run: | - curl -o lpeg.tar.gz http://www.inf.puc-rio.br/~roberto/lpeg/lpeg-1.0.2.tar.gz + curl -L -o lpeg.tar.gz https://www.inf.puc-rio.br/~roberto/lpeg/lpeg-1.0.2.tar.gz tar -xzf lpeg.tar.gz - name: Get Luafilesystem From 8b7b91ff984d49d9601f01201051b3960a9698d8 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 8 Jan 2026 12:53:06 -0800 Subject: [PATCH 488/554] more binary fixes --- .github/workflows/binaries.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/binaries.yml b/.github/workflows/binaries.yml index d916fe34..1f2acb1e 100644 --- a/.github/workflows/binaries.yml +++ b/.github/workflows/binaries.yml @@ -29,7 +29,9 @@ jobs: tar -xzf luafilesystem.tar.gz - name: Build - run: gcc -o moon '-Ilua-5.1.5/src/' bin/binaries/moon.c lpeg-1.0.2/lpvm.c lpeg-1.0.2/lpcap.c lpeg-1.0.2/lptree.c lpeg-1.0.2/lpcode.c lpeg-1.0.2/lpprint.c + run: | + mkdir -p dist + gcc -o dist/moon '-Ilua-5.1.5/src/' bin/binaries/moon.c lpeg-1.0.2/lpvm.c lpeg-1.0.2/lpcap.c lpeg-1.0.2/lptree.c lpeg-1.0.2/lpcode.c lpeg-1.0.2/lpprint.c windows: @@ -68,7 +70,9 @@ jobs: run: lua-5.1.5/src/lua.exe -v - name: Build - run: gcc -o moon.exe '-Ilua-5.1.5/src/' bin/binaries/moon.c lpeg-1.0.2/lpvm.c lpeg-1.0.2/lpcap.c lpeg-1.0.2/lptree.c lpeg-1.0.2/lpcode.c lpeg-1.0.2/lpprint.c + run: | + mkdir -p dist + gcc -o dist/moon.exe '-Ilua-5.1.5/src/' bin/binaries/moon.c lpeg-1.0.2/lpvm.c lpeg-1.0.2/lpcap.c lpeg-1.0.2/lptree.c lpeg-1.0.2/lpcode.c lpeg-1.0.2/lpprint.c From 25555f86a53c2981d2603679efd888130f16a5ac Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 8 Jan 2026 12:55:14 -0800 Subject: [PATCH 489/554] keep it coming --- .github/workflows/binaries.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/binaries.yml b/.github/workflows/binaries.yml index 1f2acb1e..51bdfc74 100644 --- a/.github/workflows/binaries.yml +++ b/.github/workflows/binaries.yml @@ -31,7 +31,7 @@ jobs: - name: Build run: | mkdir -p dist - gcc -o dist/moon '-Ilua-5.1.5/src/' bin/binaries/moon.c lpeg-1.0.2/lpvm.c lpeg-1.0.2/lpcap.c lpeg-1.0.2/lptree.c lpeg-1.0.2/lpcode.c lpeg-1.0.2/lpprint.c + gcc -o dist/moon -Ilua-5.1.5/src/ bin/binaries/moon.c lpeg-1.0.2/lpvm.c lpeg-1.0.2/lpcap.c lpeg-1.0.2/lptree.c lpeg-1.0.2/lpcode.c lpeg-1.0.2/lpprint.c lua-5.1.5/src/liblua.a -lm -ldl windows: @@ -72,7 +72,7 @@ jobs: - name: Build run: | mkdir -p dist - gcc -o dist/moon.exe '-Ilua-5.1.5/src/' bin/binaries/moon.c lpeg-1.0.2/lpvm.c lpeg-1.0.2/lpcap.c lpeg-1.0.2/lptree.c lpeg-1.0.2/lpcode.c lpeg-1.0.2/lpprint.c + gcc -o dist/moon.exe -Ilua-5.1.5/src/ bin/binaries/moon.c lpeg-1.0.2/lpvm.c lpeg-1.0.2/lpcap.c lpeg-1.0.2/lptree.c lpeg-1.0.2/lpcode.c lpeg-1.0.2/lpprint.c lua-5.1.5/src/liblua.a -lm From ad5b2eec9d21148754b1160d4948111211367c34 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 8 Jan 2026 12:58:08 -0800 Subject: [PATCH 490/554] blip --- .github/workflows/binaries.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/binaries.yml b/.github/workflows/binaries.yml index 51bdfc74..6a9d6c30 100644 --- a/.github/workflows/binaries.yml +++ b/.github/workflows/binaries.yml @@ -16,7 +16,7 @@ jobs: run: | curl -L -O https://www.lua.org/ftp/lua-5.1.5.tar.gz tar -xzf lua-5.1.5.tar.gz - cd lua-5.1.5; make + cd lua-5.1.5 && make linux - name: Get LPeg run: | @@ -51,7 +51,7 @@ jobs: run: | curl -L -O https://www.lua.org/ftp/lua-5.1.5.tar.gz tar -xzf lua-5.1.5.tar.gz - cd lua-5.1.5; make PLAT=mingw + cd lua-5.1.5 && make generic - name: Get LPeg run: | From 755bff1bd1ed088f2f310123304f1244d0e6cf99 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 8 Jan 2026 12:59:46 -0800 Subject: [PATCH 491/554] what about this --- .github/workflows/binaries.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/binaries.yml b/.github/workflows/binaries.yml index 6a9d6c30..a6ac69dc 100644 --- a/.github/workflows/binaries.yml +++ b/.github/workflows/binaries.yml @@ -16,7 +16,7 @@ jobs: run: | curl -L -O https://www.lua.org/ftp/lua-5.1.5.tar.gz tar -xzf lua-5.1.5.tar.gz - cd lua-5.1.5 && make linux + cd lua-5.1.5/src && make liblua.a MYCFLAGS=-DLUA_USE_POSIX - name: Get LPeg run: | @@ -51,7 +51,7 @@ jobs: run: | curl -L -O https://www.lua.org/ftp/lua-5.1.5.tar.gz tar -xzf lua-5.1.5.tar.gz - cd lua-5.1.5 && make generic + cd lua-5.1.5/src && make liblua.a - name: Get LPeg run: | From 2de9084a451e02c4f5a0d607ce40e1d6f4b83298 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 8 Jan 2026 13:03:11 -0800 Subject: [PATCH 492/554] test run, and upload artifacts --- .github/workflows/binaries.yml | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/.github/workflows/binaries.yml b/.github/workflows/binaries.yml index a6ac69dc..e473b449 100644 --- a/.github/workflows/binaries.yml +++ b/.github/workflows/binaries.yml @@ -31,8 +31,16 @@ jobs: - name: Build run: | mkdir -p dist - gcc -o dist/moon -Ilua-5.1.5/src/ bin/binaries/moon.c lpeg-1.0.2/lpvm.c lpeg-1.0.2/lpcap.c lpeg-1.0.2/lptree.c lpeg-1.0.2/lpcode.c lpeg-1.0.2/lpprint.c lua-5.1.5/src/liblua.a -lm -ldl + gcc -static -o dist/moon -Ilua-5.1.5/src/ bin/binaries/moon.c lpeg-1.0.2/lpvm.c lpeg-1.0.2/lpcap.c lpeg-1.0.2/lptree.c lpeg-1.0.2/lpcode.c lpeg-1.0.2/lpprint.c lua-5.1.5/src/liblua.a -lm -ldl + - name: Test run + run: dist/moon -e 'print "hello world"' + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: moon-linux + path: dist/ windows: runs-on: windows-latest @@ -63,17 +71,16 @@ jobs: curl -L -o luafilesystem.tar.gz https://github.com/keplerproject/luafilesystem/archive/v1_8_0.tar.gz tar -xzf luafilesystem.tar.gz - - name: List Files - run: Get-ChildItem -Recurse - - - name: Run Lua - run: lua-5.1.5/src/lua.exe -v - - name: Build run: | mkdir -p dist - gcc -o dist/moon.exe -Ilua-5.1.5/src/ bin/binaries/moon.c lpeg-1.0.2/lpvm.c lpeg-1.0.2/lpcap.c lpeg-1.0.2/lptree.c lpeg-1.0.2/lpcode.c lpeg-1.0.2/lpprint.c lua-5.1.5/src/liblua.a -lm - - + gcc -static -o dist/moon.exe -Ilua-5.1.5/src/ bin/binaries/moon.c lpeg-1.0.2/lpvm.c lpeg-1.0.2/lpcap.c lpeg-1.0.2/lptree.c lpeg-1.0.2/lpcode.c lpeg-1.0.2/lpprint.c lua-5.1.5/src/liblua.a -lm + - name: Test run + run: dist/moon.exe -e 'print "hello world"' + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: moon-windows + path: dist/ From fb690d6d342ecb81926950e9acd86de60e5d03d0 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 8 Jan 2026 13:04:54 -0800 Subject: [PATCH 493/554] make lua version part of matrix --- .github/workflows/binaries.yml | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/.github/workflows/binaries.yml b/.github/workflows/binaries.yml index e473b449..68a45006 100644 --- a/.github/workflows/binaries.yml +++ b/.github/workflows/binaries.yml @@ -3,9 +3,13 @@ name: "binaries" on: [push] jobs: - linux: + linux: runs-on: ubuntu-latest + strategy: + matrix: + lua_version: ["5.1.5"] + steps: - uses: actions/checkout@master @@ -14,9 +18,9 @@ jobs: - name: Setup Lua run: | - curl -L -O https://www.lua.org/ftp/lua-5.1.5.tar.gz - tar -xzf lua-5.1.5.tar.gz - cd lua-5.1.5/src && make liblua.a MYCFLAGS=-DLUA_USE_POSIX + curl -L -O https://www.lua.org/ftp/lua-${{ matrix.lua_version }}.tar.gz + tar -xzf lua-${{ matrix.lua_version }}.tar.gz + cd lua-${{ matrix.lua_version }}/src && make liblua.a MYCFLAGS=-DLUA_USE_POSIX - name: Get LPeg run: | @@ -31,20 +35,24 @@ jobs: - name: Build run: | mkdir -p dist - gcc -static -o dist/moon -Ilua-5.1.5/src/ bin/binaries/moon.c lpeg-1.0.2/lpvm.c lpeg-1.0.2/lpcap.c lpeg-1.0.2/lptree.c lpeg-1.0.2/lpcode.c lpeg-1.0.2/lpprint.c lua-5.1.5/src/liblua.a -lm -ldl + gcc -static -o dist/moon -Ilua-${{ matrix.lua_version }}/src/ bin/binaries/moon.c lpeg-1.0.2/lpvm.c lpeg-1.0.2/lpcap.c lpeg-1.0.2/lptree.c lpeg-1.0.2/lpcode.c lpeg-1.0.2/lpprint.c lua-${{ matrix.lua_version }}/src/liblua.a -lm -ldl - name: Test run run: dist/moon -e 'print "hello world"' - name: Upload artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: - name: moon-linux + name: moon-linux-lua${{ matrix.lua_version }} path: dist/ windows: runs-on: windows-latest + strategy: + matrix: + lua_version: ["5.1.5"] + steps: - uses: actions/checkout@master @@ -57,9 +65,9 @@ jobs: - name: Setup Lua run: | - curl -L -O https://www.lua.org/ftp/lua-5.1.5.tar.gz - tar -xzf lua-5.1.5.tar.gz - cd lua-5.1.5/src && make liblua.a + curl -L -O https://www.lua.org/ftp/lua-${{ matrix.lua_version }}.tar.gz + tar -xzf lua-${{ matrix.lua_version }}.tar.gz + cd lua-${{ matrix.lua_version }}/src && make liblua.a - name: Get LPeg run: | @@ -74,13 +82,13 @@ jobs: - name: Build run: | mkdir -p dist - gcc -static -o dist/moon.exe -Ilua-5.1.5/src/ bin/binaries/moon.c lpeg-1.0.2/lpvm.c lpeg-1.0.2/lpcap.c lpeg-1.0.2/lptree.c lpeg-1.0.2/lpcode.c lpeg-1.0.2/lpprint.c lua-5.1.5/src/liblua.a -lm + gcc -static -o dist/moon.exe -Ilua-${{ matrix.lua_version }}/src/ bin/binaries/moon.c lpeg-1.0.2/lpvm.c lpeg-1.0.2/lpcap.c lpeg-1.0.2/lptree.c lpeg-1.0.2/lpcode.c lpeg-1.0.2/lpprint.c lua-${{ matrix.lua_version }}/src/liblua.a -lm - name: Test run run: dist/moon.exe -e 'print "hello world"' - name: Upload artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: - name: moon-windows + name: moon-windows-lua${{ matrix.lua_version }} path: dist/ From c8c945fa2cf821ff9c230c57304983f8dee6c3d3 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 8 Jan 2026 13:14:47 -0800 Subject: [PATCH 494/554] add makefile equivalent for making dist/moon --- .github/workflows/binaries.yml | 8 ++++++-- Makefile | 23 ++++++++++++++++++++++- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/.github/workflows/binaries.yml b/.github/workflows/binaries.yml index 68a45006..b04cc059 100644 --- a/.github/workflows/binaries.yml +++ b/.github/workflows/binaries.yml @@ -38,7 +38,9 @@ jobs: gcc -static -o dist/moon -Ilua-${{ matrix.lua_version }}/src/ bin/binaries/moon.c lpeg-1.0.2/lpvm.c lpeg-1.0.2/lpcap.c lpeg-1.0.2/lptree.c lpeg-1.0.2/lpcode.c lpeg-1.0.2/lpprint.c lua-${{ matrix.lua_version }}/src/liblua.a -lm -ldl - name: Test run - run: dist/moon -e 'print "hello world"' + run: | + dist/moon -h + dist/moon -e 'print "hello world"' - name: Upload artifact uses: actions/upload-artifact@v6 @@ -85,7 +87,9 @@ jobs: gcc -static -o dist/moon.exe -Ilua-${{ matrix.lua_version }}/src/ bin/binaries/moon.c lpeg-1.0.2/lpvm.c lpeg-1.0.2/lpcap.c lpeg-1.0.2/lptree.c lpeg-1.0.2/lpcode.c lpeg-1.0.2/lpprint.c lua-${{ matrix.lua_version }}/src/liblua.a -lm - name: Test run - run: dist/moon.exe -e 'print "hello world"' + run: | + dist/moon.exe -h + dist/moon.exe -e 'print "hello world"' - name: Upload artifact uses: actions/upload-artifact@v6 diff --git a/Makefile b/Makefile index ed924438..8c76c216 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,10 @@ LUAROCKS = luarocks --lua-version=$(LUA_VERSION) LUA_PATH_MAKE = $(shell $(LUAROCKS) path --lr-path);./?.lua;./?/init.lua LUA_CPATH_MAKE = $(shell $(LUAROCKS) path --lr-cpath);./?.so -.PHONY: test local build watch lint count show +LUA_SRC_VERSION ?= 5.1.5 +LPEG_VERSION ?= 1.0.2 + +.PHONY: test local build watch lint count show test_binary build: LUA_PATH='$(LUA_PATH_MAKE)' LUA_CPATH='$(LUA_CPATH_MAKE)' $(LUA) bin/moonc moon/ moonscript/ @@ -44,3 +47,21 @@ lint: count: wc -l $$(git ls-files | grep 'moon$$') | sort -n | tail + +# Binary build targets for local verification (Linux only) +lua-$(LUA_SRC_VERSION)/src/liblua.a: + curl -L -O https://www.lua.org/ftp/lua-$(LUA_SRC_VERSION).tar.gz + tar -xzf lua-$(LUA_SRC_VERSION).tar.gz + cd lua-$(LUA_SRC_VERSION)/src && make liblua.a MYCFLAGS=-DLUA_USE_POSIX + +lpeg-$(LPEG_VERSION)/lptree.c: + curl -L -o lpeg.tar.gz https://www.inf.puc-rio.br/~roberto/lpeg/lpeg-$(LPEG_VERSION).tar.gz + tar -xzf lpeg.tar.gz + +dist/moon: lua-$(LUA_SRC_VERSION)/src/liblua.a lpeg-$(LPEG_VERSION)/lptree.c + mkdir -p dist + gcc -static -o dist/moon -Ilua-$(LUA_SRC_VERSION)/src/ bin/binaries/moon.c lpeg-$(LPEG_VERSION)/lpvm.c lpeg-$(LPEG_VERSION)/lpcap.c lpeg-$(LPEG_VERSION)/lptree.c lpeg-$(LPEG_VERSION)/lpcode.c lpeg-$(LPEG_VERSION)/lpprint.c lua-$(LUA_SRC_VERSION)/src/liblua.a -lm -ldl + +test_binary: dist/moon + dist/moon -h + dist/moon -e 'print "hello world"' From 905a24a44734718309aba323eb85f35778810c9e Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 8 Jan 2026 13:16:16 -0800 Subject: [PATCH 495/554] try to fix windows build --- .github/workflows/binaries.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/binaries.yml b/.github/workflows/binaries.yml index b04cc059..88ad11ba 100644 --- a/.github/workflows/binaries.yml +++ b/.github/workflows/binaries.yml @@ -55,6 +55,10 @@ jobs: matrix: lua_version: ["5.1.5"] + defaults: + run: + shell: msys2 {0} + steps: - uses: actions/checkout@master From 6284a0cf798a9b8a10a2e8de80c130289294147d Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 8 Jan 2026 13:33:01 -0800 Subject: [PATCH 496/554] working through binaries some more --- Makefile | 24 ++++++++++++++++++++---- bin/binaries/moon.c | 29 ++++++++++++++++++++++++++++- bin/binaries/moonscript.c | 35 +++++++++++++++++++++++++++++++++++ moon.lua | 1 - moonscript.lua | 1 - 5 files changed, 83 insertions(+), 7 deletions(-) create mode 100644 bin/binaries/moonscript.c delete mode 100644 moon.lua delete mode 100644 moonscript.lua diff --git a/Makefile b/Makefile index 8c76c216..66e2a752 100644 --- a/Makefile +++ b/Makefile @@ -58,10 +58,26 @@ lpeg-$(LPEG_VERSION)/lptree.c: curl -L -o lpeg.tar.gz https://www.inf.puc-rio.br/~roberto/lpeg/lpeg-$(LPEG_VERSION).tar.gz tar -xzf lpeg.tar.gz -dist/moon: lua-$(LUA_SRC_VERSION)/src/liblua.a lpeg-$(LPEG_VERSION)/lptree.c +bin/binaries/moonscript.h: moonscript/*.lua moon/*.lua + bin/splat.moon -l moonscript moonscript moon > moonscript.lua + xxd -i moonscript.lua > $@ + rm moonscript.lua + +dist/moon: lua-$(LUA_SRC_VERSION)/src/liblua.a lpeg-$(LPEG_VERSION)/lptree.c bin/binaries/moonscript.h mkdir -p dist - gcc -static -o dist/moon -Ilua-$(LUA_SRC_VERSION)/src/ bin/binaries/moon.c lpeg-$(LPEG_VERSION)/lpvm.c lpeg-$(LPEG_VERSION)/lpcap.c lpeg-$(LPEG_VERSION)/lptree.c lpeg-$(LPEG_VERSION)/lpcode.c lpeg-$(LPEG_VERSION)/lpprint.c lua-$(LUA_SRC_VERSION)/src/liblua.a -lm -ldl + gcc -static -o dist/moon \ + -Ilua-$(LUA_SRC_VERSION)/src/ \ + -Ilpeg-$(LPEG_VERSION)/ \ + -Ibin/binaries/ \ + bin/binaries/moon.c \ + bin/binaries/moonscript.c \ + lpeg-$(LPEG_VERSION)/lpvm.c \ + lpeg-$(LPEG_VERSION)/lpcap.c \ + lpeg-$(LPEG_VERSION)/lptree.c \ + lpeg-$(LPEG_VERSION)/lpcode.c \ + lpeg-$(LPEG_VERSION)/lpprint.c \ + lua-$(LUA_SRC_VERSION)/src/liblua.a \ + -lm -ldl test_binary: dist/moon - dist/moon -h - dist/moon -e 'print "hello world"' + dist/moon diff --git a/bin/binaries/moon.c b/bin/binaries/moon.c index ea668ed9..344e3656 100644 --- a/bin/binaries/moon.c +++ b/bin/binaries/moon.c @@ -1,4 +1,31 @@ +#include +#include +#include +#include + +// from moonscript.c +extern int luaopen_moonscript(lua_State *l); -// this does nothing until we get a build working for all deps int main(int argc, char **argv) { + lua_State *l = luaL_newstate(); + luaL_openlibs(l); + + // Load moonscript (this also loads lpeg) + luaopen_moonscript(l); + lua_pop(l, 1); // pop the return value + + // Simple test: require moonscript and compile something + const char *test_code = + "local moonscript = require('moonscript')\n" + "local code = moonscript.to_lua('print \"hello from moonscript\"')\n" + "print(code)\n" + "loadstring(code)()\n"; + + if (luaL_dostring(l, test_code) != 0) { + fprintf(stderr, "Test failed: %s\n", lua_tostring(l, -1)); + return 1; + } + + lua_close(l); + return 0; } diff --git a/bin/binaries/moonscript.c b/bin/binaries/moonscript.c new file mode 100644 index 00000000..deed4f91 --- /dev/null +++ b/bin/binaries/moonscript.c @@ -0,0 +1,35 @@ +#include +#include +#include +#include + +#include "moonscript.h" + +// put whatever is on top of stack into package.loaded under name if something +// is not already there +void setloaded(lua_State* l, const char* name) { + int top = lua_gettop(l); + lua_getglobal(l, "package"); + lua_getfield(l, -1, "loaded"); + lua_getfield(l, -1, name); + if (lua_isnil(l, -1)) { + lua_pop(l, 1); + lua_pushvalue(l, top); + lua_setfield(l, -2, name); + } + + lua_settop(l, top); +} + +extern int luaopen_lpeg(lua_State *l); + +LUALIB_API int luaopen_moonscript(lua_State *l) { + luaopen_lpeg(l); + setloaded(l, "lpeg"); + + if (luaL_loadbuffer(l, (const char *)moonscript_lua, moonscript_lua_len, "moonscript.lua") == 0) { + lua_call(l, 0, 1); + return 1; + } + return 0; +} diff --git a/moon.lua b/moon.lua deleted file mode 100644 index 6b1536fd..00000000 --- a/moon.lua +++ /dev/null @@ -1 +0,0 @@ -return require "moon.init" diff --git a/moonscript.lua b/moonscript.lua deleted file mode 100644 index dd876be9..00000000 --- a/moonscript.lua +++ /dev/null @@ -1 +0,0 @@ -return require "moonscript.init" From 8fe8c2a41f7c515e478a72ae85c3c054957fe661 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 8 Jan 2026 13:40:20 -0800 Subject: [PATCH 497/554] convert moon.moon -> moon.h, and run it through the moon.c entry point --- Makefile | 7 ++++++- bin/binaries/moon.c | 28 +++++++++++++++++++--------- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index 66e2a752..d68b6812 100644 --- a/Makefile +++ b/Makefile @@ -63,7 +63,12 @@ bin/binaries/moonscript.h: moonscript/*.lua moon/*.lua xxd -i moonscript.lua > $@ rm moonscript.lua -dist/moon: lua-$(LUA_SRC_VERSION)/src/liblua.a lpeg-$(LPEG_VERSION)/lptree.c bin/binaries/moonscript.h +bin/binaries/moon.h: bin/moon + awk 'FNR>1' bin/moon > moon.lua + xxd -i moon.lua > $@ + rm moon.lua + +dist/moon: lua-$(LUA_SRC_VERSION)/src/liblua.a lpeg-$(LPEG_VERSION)/lptree.c bin/binaries/moonscript.h bin/binaries/moon.h mkdir -p dist gcc -static -o dist/moon \ -Ilua-$(LUA_SRC_VERSION)/src/ \ diff --git a/bin/binaries/moon.c b/bin/binaries/moon.c index 344e3656..f668d436 100644 --- a/bin/binaries/moon.c +++ b/bin/binaries/moon.c @@ -3,6 +3,8 @@ #include #include +#include "moon.h" // the CLI script + // from moonscript.c extern int luaopen_moonscript(lua_State *l); @@ -12,17 +14,25 @@ int main(int argc, char **argv) { // Load moonscript (this also loads lpeg) luaopen_moonscript(l); - lua_pop(l, 1); // pop the return value + lua_pop(l, 1); - // Simple test: require moonscript and compile something - const char *test_code = - "local moonscript = require('moonscript')\n" - "local code = moonscript.to_lua('print \"hello from moonscript\"')\n" - "print(code)\n" - "loadstring(code)()\n"; + // Set up arg table + lua_newtable(l); + lua_pushstring(l, "moon"); + lua_rawseti(l, -2, -1); + for (int i = 0; i < argc; i++) { + lua_pushstring(l, argv[i]); + lua_rawseti(l, -2, i); + } + lua_setglobal(l, "arg"); - if (luaL_dostring(l, test_code) != 0) { - fprintf(stderr, "Test failed: %s\n", lua_tostring(l, -1)); + // Load and execute the moon CLI script + if (luaL_loadbuffer(l, (const char *)moon_lua, moon_lua_len, "moon") != 0) { + fprintf(stderr, "Failed to load moon: %s\n", lua_tostring(l, -1)); + return 1; + } + if (lua_pcall(l, 0, 0, 0) != 0) { + fprintf(stderr, "Error: %s\n", lua_tostring(l, -1)); return 1; } From ae5d0c7af0efd1c20026c53eec255b804610f760 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 8 Jan 2026 13:47:46 -0800 Subject: [PATCH 498/554] try a different stage to download headers --- .github/workflows/binaries.yml | 74 +++++++++++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 2 deletions(-) diff --git a/.github/workflows/binaries.yml b/.github/workflows/binaries.yml index 88ad11ba..8537acaf 100644 --- a/.github/workflows/binaries.yml +++ b/.github/workflows/binaries.yml @@ -3,8 +3,41 @@ name: "binaries" on: [push] jobs: + generate-headers: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + + - uses: leafo/gh-actions-lua@master + with: + luaVersion: "5.1" + + - uses: leafo/gh-actions-luarocks@master + + - name: Install dependencies + run: | + luarocks install argparse + luarocks make + + - name: Generate moonscript.h + run: | + bin/splat.moon -l moonscript moonscript moon > moonscript.lua + xxd -i moonscript.lua > bin/binaries/moonscript.h + + - name: Generate moon.h + run: | + awk 'FNR>1' bin/moon > moon.lua + xxd -i moon.lua > bin/binaries/moon.h + + - name: Upload headers + uses: actions/upload-artifact@v6 + with: + name: generated-headers + path: bin/binaries/*.h + linux: runs-on: ubuntu-latest + needs: generate-headers strategy: matrix: @@ -13,6 +46,12 @@ jobs: steps: - uses: actions/checkout@master + - name: Download headers + uses: actions/download-artifact@v4 + with: + name: generated-headers + path: bin/binaries/ + - name: Show GCC run: gcc -v @@ -35,7 +74,19 @@ jobs: - name: Build run: | mkdir -p dist - gcc -static -o dist/moon -Ilua-${{ matrix.lua_version }}/src/ bin/binaries/moon.c lpeg-1.0.2/lpvm.c lpeg-1.0.2/lpcap.c lpeg-1.0.2/lptree.c lpeg-1.0.2/lpcode.c lpeg-1.0.2/lpprint.c lua-${{ matrix.lua_version }}/src/liblua.a -lm -ldl + gcc -static -o dist/moon \ + -Ilua-${{ matrix.lua_version }}/src/ \ + -Ilpeg-1.0.2/ \ + -Ibin/binaries/ \ + bin/binaries/moon.c \ + bin/binaries/moonscript.c \ + lpeg-1.0.2/lpvm.c \ + lpeg-1.0.2/lpcap.c \ + lpeg-1.0.2/lptree.c \ + lpeg-1.0.2/lpcode.c \ + lpeg-1.0.2/lpprint.c \ + lua-${{ matrix.lua_version }}/src/liblua.a \ + -lm -ldl - name: Test run run: | @@ -50,6 +101,7 @@ jobs: windows: runs-on: windows-latest + needs: generate-headers strategy: matrix: @@ -62,6 +114,12 @@ jobs: steps: - uses: actions/checkout@master + - name: Download headers + uses: actions/download-artifact@v4 + with: + name: generated-headers + path: bin/binaries/ + - uses: msys2/setup-msys2@v2 with: install: gcc make curl @@ -88,7 +146,19 @@ jobs: - name: Build run: | mkdir -p dist - gcc -static -o dist/moon.exe -Ilua-${{ matrix.lua_version }}/src/ bin/binaries/moon.c lpeg-1.0.2/lpvm.c lpeg-1.0.2/lpcap.c lpeg-1.0.2/lptree.c lpeg-1.0.2/lpcode.c lpeg-1.0.2/lpprint.c lua-${{ matrix.lua_version }}/src/liblua.a -lm + gcc -static -o dist/moon.exe \ + -Ilua-${{ matrix.lua_version }}/src/ \ + -Ilpeg-1.0.2/ \ + -Ibin/binaries/ \ + bin/binaries/moon.c \ + bin/binaries/moonscript.c \ + lpeg-1.0.2/lpvm.c \ + lpeg-1.0.2/lpcap.c \ + lpeg-1.0.2/lptree.c \ + lpeg-1.0.2/lpcode.c \ + lpeg-1.0.2/lpprint.c \ + lua-${{ matrix.lua_version }}/src/liblua.a \ + -lm - name: Test run run: | From 5c920e515115ed06409fd6691bda24026ea1c786 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 8 Jan 2026 13:58:42 -0800 Subject: [PATCH 499/554] make specs look for the init files (shouldn't loadkit do this??) --- spec/helpers.moon | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spec/helpers.moon b/spec/helpers.moon index 45545b91..ddfcddb1 100644 --- a/spec/helpers.moon +++ b/spec/helpers.moon @@ -24,6 +24,12 @@ with_dev = (fn) -> setup -> _G.require = (mod) -> + switch mod + when "moonscript" + "moonscript.init" + when "moon" + "moon.init" + return dev_cache[mod] if dev_cache[mod] testable = mod\match("moonscript%.") or mod == "moonscript" or From ef9f892841bc83ce196a8998d2ce68a32582a74e Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 8 Jan 2026 14:06:37 -0800 Subject: [PATCH 500/554] add support for embedding argparse --- Makefile | 10 +++++++++- bin/binaries/moonscript.c | 6 ++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index d68b6812..3c1aaab2 100644 --- a/Makefile +++ b/Makefile @@ -49,6 +49,9 @@ count: wc -l $$(git ls-files | grep 'moon$$') | sort -n | tail # Binary build targets for local verification (Linux only) +lua_modules: + luarocks install argparse --tree=lua_modules + lua-$(LUA_SRC_VERSION)/src/liblua.a: curl -L -O https://www.lua.org/ftp/lua-$(LUA_SRC_VERSION).tar.gz tar -xzf lua-$(LUA_SRC_VERSION).tar.gz @@ -68,7 +71,12 @@ bin/binaries/moon.h: bin/moon xxd -i moon.lua > $@ rm moon.lua -dist/moon: lua-$(LUA_SRC_VERSION)/src/liblua.a lpeg-$(LPEG_VERSION)/lptree.c bin/binaries/moonscript.h bin/binaries/moon.h +bin/binaries/argparse.h: lua_modules + bin/splat.moon -l argparse $$(find lua_modules/share/lua -name "*.lua" -exec dirname {} \; | head -1) > argparse.lua + xxd -i argparse.lua > $@ + rm argparse.lua + +dist/moon: lua-$(LUA_SRC_VERSION)/src/liblua.a lpeg-$(LPEG_VERSION)/lptree.c bin/binaries/moonscript.h bin/binaries/moon.h bin/binaries/argparse.h mkdir -p dist gcc -static -o dist/moon \ -Ilua-$(LUA_SRC_VERSION)/src/ \ diff --git a/bin/binaries/moonscript.c b/bin/binaries/moonscript.c index deed4f91..606242dd 100644 --- a/bin/binaries/moonscript.c +++ b/bin/binaries/moonscript.c @@ -4,6 +4,7 @@ #include #include "moonscript.h" +#include "argparse.h" // put whatever is on top of stack into package.loaded under name if something // is not already there @@ -27,6 +28,11 @@ LUALIB_API int luaopen_moonscript(lua_State *l) { luaopen_lpeg(l); setloaded(l, "lpeg"); + // Load argparse (splat output sets up package.preload) + if (luaL_loadbuffer(l, (const char *)argparse_lua, argparse_lua_len, "argparse.lua") == 0) { + lua_call(l, 0, 0); + } + if (luaL_loadbuffer(l, (const char *)moonscript_lua, moonscript_lua_len, "moonscript.lua") == 0) { lua_call(l, 0, 1); return 1; From 5bf04b131a35ce5a512baf5c0ea5294c44e400f1 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 8 Jan 2026 14:10:40 -0800 Subject: [PATCH 501/554] generate argparse.h in the workflow --- .github/workflows/binaries.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/binaries.yml b/.github/workflows/binaries.yml index 8537acaf..39c90209 100644 --- a/.github/workflows/binaries.yml +++ b/.github/workflows/binaries.yml @@ -29,6 +29,12 @@ jobs: awk 'FNR>1' bin/moon > moon.lua xxd -i moon.lua > bin/binaries/moon.h + - name: Generate argparse.h + run: | + luarocks install argparse --tree=lua_modules + bin/splat.moon -l argparse $(find lua_modules/share/lua -name "*.lua" -exec dirname {} \; | head -1) > argparse.lua + xxd -i argparse.lua > bin/binaries/argparse.h + - name: Upload headers uses: actions/upload-artifact@v6 with: From 158f7fccfe5c5ac1ba966bc5b01346fbd3f29ee7 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 8 Jan 2026 14:11:58 -0800 Subject: [PATCH 502/554] woops, fix the module name rewrite --- spec/helpers.moon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/helpers.moon b/spec/helpers.moon index ddfcddb1..caf885c2 100644 --- a/spec/helpers.moon +++ b/spec/helpers.moon @@ -24,7 +24,7 @@ with_dev = (fn) -> setup -> _G.require = (mod) -> - switch mod + mod = switch mod when "moonscript" "moonscript.init" when "moon" From bf965ef40397c883336ed0b888a0710f73df8f65 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 8 Jan 2026 14:24:55 -0800 Subject: [PATCH 503/554] fix splat for argparse dependency --- .github/workflows/binaries.yml | 4 ++-- Makefile | 5 ++--- bin/splat.moon | 15 ++++++++++----- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/.github/workflows/binaries.yml b/.github/workflows/binaries.yml index 39c90209..b8743605 100644 --- a/.github/workflows/binaries.yml +++ b/.github/workflows/binaries.yml @@ -32,8 +32,8 @@ jobs: - name: Generate argparse.h run: | luarocks install argparse --tree=lua_modules - bin/splat.moon -l argparse $(find lua_modules/share/lua -name "*.lua" -exec dirname {} \; | head -1) > argparse.lua - xxd -i argparse.lua > bin/binaries/argparse.h + bin/splat.moon --strip-prefix -l argparse $(find lua_modules/share/lua -name "argparse.lua" -exec dirname {} \; | head -1) > bin/binaries/argparse.lua + xxd -i -n argparse_lua bin/binaries/argparse.lua > bin/binaries/argparse.h - name: Upload headers uses: actions/upload-artifact@v6 diff --git a/Makefile b/Makefile index 3c1aaab2..84ebaf4c 100644 --- a/Makefile +++ b/Makefile @@ -72,9 +72,8 @@ bin/binaries/moon.h: bin/moon rm moon.lua bin/binaries/argparse.h: lua_modules - bin/splat.moon -l argparse $$(find lua_modules/share/lua -name "*.lua" -exec dirname {} \; | head -1) > argparse.lua - xxd -i argparse.lua > $@ - rm argparse.lua + bin/splat.moon --strip-prefix -l argparse $$(find lua_modules/share/lua -name "argparse.lua" -exec dirname {} \; | head -1) > bin/binaries/argparse.lua + xxd -i -n argparse_lua bin/binaries/argparse.lua > $@ dist/moon: lua-$(LUA_SRC_VERSION)/src/liblua.a lpeg-$(LPEG_VERSION)/lptree.c bin/binaries/moonscript.h bin/binaries/moon.h bin/binaries/argparse.h mkdir -p dist diff --git a/bin/splat.moon b/bin/splat.moon index 15c1a5a8..a7009948 100755 --- a/bin/splat.moon +++ b/bin/splat.moon @@ -1,16 +1,18 @@ #!/usr/bin/env moon argparse = require "argparse" +normalize = (path) -> + path\match("(.-)/*$").."/" + parser = argparse "splat.moon", "Concatenate a collection of Lua modules into a single file" parser\option("--load -l", "Module names that will be load on require")\count "*" +parser\flag("--strip-prefix -s", "Strip directory prefix from module names") parser\argument("directories", "Directories to scan for Lua modules")\args "+" args = parser\parse [v for _, v in ipairs _G.arg] dirs = args.directories - -normalize = (path) -> - path\match("(.-)/*$").."/" +strip_prefix = args.strip_prefix lfs = require "lfs" scan_directory = (root, patt, collected={}) -> @@ -27,7 +29,9 @@ scan_directory = (root, patt, collected={}) -> collected -path_to_module_name = (path) -> +path_to_module_name = (path, prefix) -> + if prefix and path\sub(1, #prefix) == prefix + path = path\sub(#prefix + 1) (path\match("(.-)%.lua")\gsub("/", ".")) each_line = (text) -> @@ -50,8 +54,9 @@ write_module = (name, text) -> modules = {} for dir in *dirs files = scan_directory dir, "%.lua$" + prefix = strip_prefix and normalize(dir) or nil chunks = for path in *files - module_name = path_to_module_name path + module_name = path_to_module_name path, prefix content = io.open(path)\read"*a" modules[module_name] = true {module_name, content} From 57009b142a11b5a63e2914a44660e6c3758ab6b3 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 9 Jan 2026 15:37:16 -0800 Subject: [PATCH 504/554] get moonc buildin --- Makefile | 29 ++++++++++++++++++++++++++++- bin/splat.moon | 3 +++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 84ebaf4c..c3c0868b 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,7 @@ LUA_CPATH_MAKE = $(shell $(LUAROCKS) path --lr-cpath);./?.so LUA_SRC_VERSION ?= 5.1.5 LPEG_VERSION ?= 1.0.2 +LFS_VERSION ?= 1_8_0 .PHONY: test local build watch lint count show test_binary @@ -61,6 +62,10 @@ lpeg-$(LPEG_VERSION)/lptree.c: curl -L -o lpeg.tar.gz https://www.inf.puc-rio.br/~roberto/lpeg/lpeg-$(LPEG_VERSION).tar.gz tar -xzf lpeg.tar.gz +luafilesystem-$(LFS_VERSION)/src/lfs.c: + curl -L -o luafilesystem.tar.gz https://github.com/keplerproject/luafilesystem/archive/v$(LFS_VERSION).tar.gz + tar -xzf luafilesystem.tar.gz + bin/binaries/moonscript.h: moonscript/*.lua moon/*.lua bin/splat.moon -l moonscript moonscript moon > moonscript.lua xxd -i moonscript.lua > $@ @@ -75,7 +80,12 @@ bin/binaries/argparse.h: lua_modules bin/splat.moon --strip-prefix -l argparse $$(find lua_modules/share/lua -name "argparse.lua" -exec dirname {} \; | head -1) > bin/binaries/argparse.lua xxd -i -n argparse_lua bin/binaries/argparse.lua > $@ -dist/moon: lua-$(LUA_SRC_VERSION)/src/liblua.a lpeg-$(LPEG_VERSION)/lptree.c bin/binaries/moonscript.h bin/binaries/moon.h bin/binaries/argparse.h +bin/binaries/moonc.h: bin/moonc + awk 'FNR>1' bin/moonc > moonc.lua + xxd -i moonc.lua > $@ + rm moonc.lua + +dist/moon: lua-$(LUA_SRC_VERSION)/src/liblua.a lpeg-$(LPEG_VERSION)/lptree.c bin/binaries/moonscript.h bin/binaries/moon.h bin/binaries/argparse.h bin/binaries/moon.c bin/binaries/moonscript.c mkdir -p dist gcc -static -o dist/moon \ -Ilua-$(LUA_SRC_VERSION)/src/ \ @@ -91,5 +101,22 @@ dist/moon: lua-$(LUA_SRC_VERSION)/src/liblua.a lpeg-$(LPEG_VERSION)/lptree.c bin lua-$(LUA_SRC_VERSION)/src/liblua.a \ -lm -ldl +dist/moonc: lua-$(LUA_SRC_VERSION)/src/liblua.a lpeg-$(LPEG_VERSION)/lptree.c luafilesystem-$(LFS_VERSION)/src/lfs.c bin/binaries/moonscript.h bin/binaries/moonc.h bin/binaries/argparse.h bin/binaries/moonc.c bin/binaries/moonscript.c + mkdir -p dist + gcc -static -o dist/moonc \ + -Ilua-$(LUA_SRC_VERSION)/src/ \ + -Ilpeg-$(LPEG_VERSION)/ \ + -Ibin/binaries/ \ + bin/binaries/moonc.c \ + bin/binaries/moonscript.c \ + lpeg-$(LPEG_VERSION)/lpvm.c \ + lpeg-$(LPEG_VERSION)/lpcap.c \ + lpeg-$(LPEG_VERSION)/lptree.c \ + lpeg-$(LPEG_VERSION)/lpcode.c \ + lpeg-$(LPEG_VERSION)/lpprint.c \ + luafilesystem-$(LFS_VERSION)/src/lfs.c \ + lua-$(LUA_SRC_VERSION)/src/liblua.a \ + -lm -ldl + test_binary: dist/moon dist/moon diff --git a/bin/splat.moon b/bin/splat.moon index a7009948..d6127042 100755 --- a/bin/splat.moon +++ b/bin/splat.moon @@ -1,6 +1,9 @@ #!/usr/bin/env moon argparse = require "argparse" +-- TODO: it would be cool if you could just point this at a luarocks tree, pass a list of top level module names, and it figures it out for you. +-- Perhaps even merge the header generation into here as well to avoid using xxd + normalize = (path) -> path\match("(.-)/*$").."/" From dc1edf1d5f82d4d8b76be7a728a319b03f70c64a Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 9 Jan 2026 15:55:53 -0800 Subject: [PATCH 505/554] add moonc compile to binaries workflow --- .github/workflows/binaries.yml | 35 ++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/.github/workflows/binaries.yml b/.github/workflows/binaries.yml index b8743605..0fd0053c 100644 --- a/.github/workflows/binaries.yml +++ b/.github/workflows/binaries.yml @@ -35,6 +35,11 @@ jobs: bin/splat.moon --strip-prefix -l argparse $(find lua_modules/share/lua -name "argparse.lua" -exec dirname {} \; | head -1) > bin/binaries/argparse.lua xxd -i -n argparse_lua bin/binaries/argparse.lua > bin/binaries/argparse.h + - name: Generate moonc.h + run: | + awk 'FNR>1' bin/moonc > moonc.lua + xxd -i moonc.lua > bin/binaries/moonc.h + - name: Upload headers uses: actions/upload-artifact@v6 with: @@ -93,11 +98,26 @@ jobs: lpeg-1.0.2/lpprint.c \ lua-${{ matrix.lua_version }}/src/liblua.a \ -lm -ldl + gcc -static -o dist/moonc \ + -Ilua-${{ matrix.lua_version }}/src/ \ + -Ilpeg-1.0.2/ \ + -Ibin/binaries/ \ + bin/binaries/moonc.c \ + bin/binaries/moonscript.c \ + lpeg-1.0.2/lpvm.c \ + lpeg-1.0.2/lpcap.c \ + lpeg-1.0.2/lptree.c \ + lpeg-1.0.2/lpcode.c \ + lpeg-1.0.2/lpprint.c \ + luafilesystem-1_8_0/src/lfs.c \ + lua-${{ matrix.lua_version }}/src/liblua.a \ + -lm -ldl - name: Test run run: | dist/moon -h dist/moon -e 'print "hello world"' + dist/moonc -h - name: Upload artifact uses: actions/upload-artifact@v6 @@ -165,11 +185,26 @@ jobs: lpeg-1.0.2/lpprint.c \ lua-${{ matrix.lua_version }}/src/liblua.a \ -lm + gcc -static -o dist/moonc.exe \ + -Ilua-${{ matrix.lua_version }}/src/ \ + -Ilpeg-1.0.2/ \ + -Ibin/binaries/ \ + bin/binaries/moonc.c \ + bin/binaries/moonscript.c \ + lpeg-1.0.2/lpvm.c \ + lpeg-1.0.2/lpcap.c \ + lpeg-1.0.2/lptree.c \ + lpeg-1.0.2/lpcode.c \ + lpeg-1.0.2/lpprint.c \ + luafilesystem-1_8_0/src/lfs.c \ + lua-${{ matrix.lua_version }}/src/liblua.a \ + -lm - name: Test run run: | dist/moon.exe -h dist/moon.exe -e 'print "hello world"' + dist/moonc.exe -h - name: Upload artifact uses: actions/upload-artifact@v6 From bbd101517bd9d5b541901a4ce7c32070f2371fba Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 9 Jan 2026 16:05:05 -0800 Subject: [PATCH 506/554] forgot a file --- bin/binaries/moonc.c | 55 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 bin/binaries/moonc.c diff --git a/bin/binaries/moonc.c b/bin/binaries/moonc.c new file mode 100644 index 00000000..9cd9a67b --- /dev/null +++ b/bin/binaries/moonc.c @@ -0,0 +1,55 @@ +#include +#include +#include +#include + +#include "moonc.h" // the CLI script + +// from moonscript.c +extern int luaopen_moonscript(lua_State *l); + +// from lfs.c +extern int luaopen_lfs(lua_State *l); + +int main(int argc, char **argv) { + lua_State *l = luaL_newstate(); + luaL_openlibs(l); + + // Load moonscript (this also loads lpeg and argparse) + luaopen_moonscript(l); + lua_pop(l, 1); + + // Load luafilesystem and register it in package.loaded + int nresults = luaopen_lfs(l); + if (nresults > 0) { + lua_getglobal(l, "package"); + lua_getfield(l, -1, "loaded"); + lua_pushvalue(l, -3); // push lfs table + lua_setfield(l, -2, "lfs"); + lua_pop(l, 2); // pop loaded, package + } + lua_pop(l, nresults); + + // Set up arg table + lua_newtable(l); + lua_pushstring(l, "moonc"); + lua_rawseti(l, -2, -1); + for (int i = 0; i < argc; i++) { + lua_pushstring(l, argv[i]); + lua_rawseti(l, -2, i); + } + lua_setglobal(l, "arg"); + + // Load and execute the moonc CLI script + if (luaL_loadbuffer(l, (const char *)moonc_lua, moonc_lua_len, "moonc") != 0) { + fprintf(stderr, "Failed to load moonc: %s\n", lua_tostring(l, -1)); + return 1; + } + if (lua_pcall(l, 0, 0, 0) != 0) { + fprintf(stderr, "Error: %s\n", lua_tostring(l, -1)); + return 1; + } + + lua_close(l); + return 0; +} From b00d4a6400803fe738ff5941aac820adf91029b1 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 9 Jan 2026 16:42:09 -0800 Subject: [PATCH 507/554] better artifact naming, auto publishing to release --- .github/workflows/binaries.yml | 46 +++++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/.github/workflows/binaries.yml b/.github/workflows/binaries.yml index 0fd0053c..7f7ec1da 100644 --- a/.github/workflows/binaries.yml +++ b/.github/workflows/binaries.yml @@ -57,6 +57,14 @@ jobs: steps: - uses: actions/checkout@master + - name: Set version suffix + run: | + if [[ "${{ github.ref_type }}" == "tag" ]]; then + echo "VERSION_SUFFIX=${{ github.ref_name }}" >> $GITHUB_ENV + else + echo "VERSION_SUFFIX=$(git rev-parse --short HEAD)" >> $GITHUB_ENV + fi + - name: Download headers uses: actions/download-artifact@v4 with: @@ -122,9 +130,21 @@ jobs: - name: Upload artifact uses: actions/upload-artifact@v6 with: - name: moon-linux-lua${{ matrix.lua_version }} + name: moonscript-${{ env.VERSION_SUFFIX }}-linux-lua${{ matrix.lua_version }} path: dist/ + - name: Package for release + if: github.ref_type == 'tag' + run: | + cd dist + tar -czvf ../moonscript-${{ env.VERSION_SUFFIX }}-linux-x86_64.tar.gz * + + - name: Upload to release + if: github.ref_type == 'tag' + uses: softprops/action-gh-release@v2 + with: + files: moonscript-${{ env.VERSION_SUFFIX }}-linux-x86_64.tar.gz + windows: runs-on: windows-latest needs: generate-headers @@ -140,6 +160,14 @@ jobs: steps: - uses: actions/checkout@master + - name: Set version suffix + run: | + if [[ "${{ github.ref_type }}" == "tag" ]]; then + echo "VERSION_SUFFIX=${{ github.ref_name }}" >> $GITHUB_ENV + else + echo "VERSION_SUFFIX=$(git rev-parse --short HEAD)" >> $GITHUB_ENV + fi + - name: Download headers uses: actions/download-artifact@v4 with: @@ -148,7 +176,7 @@ jobs: - uses: msys2/setup-msys2@v2 with: - install: gcc make curl + install: gcc make curl zip - name: Show GCC run: gcc -v @@ -209,5 +237,17 @@ jobs: - name: Upload artifact uses: actions/upload-artifact@v6 with: - name: moon-windows-lua${{ matrix.lua_version }} + name: moonscript-${{ env.VERSION_SUFFIX }}-windows-lua${{ matrix.lua_version }} path: dist/ + + - name: Package for release + if: github.ref_type == 'tag' + run: | + cd dist + zip ../moonscript-${{ env.VERSION_SUFFIX }}-windows-x86_64.zip * + + - name: Upload to release + if: github.ref_type == 'tag' + uses: softprops/action-gh-release@v2 + with: + files: moonscript-${{ env.VERSION_SUFFIX }}-windows-x86_64.zip From 2429bb8097f8d2457458c1d21a961df19c52fb69 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 9 Jan 2026 16:49:37 -0800 Subject: [PATCH 508/554] fix order of operations --- .github/workflows/binaries.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/binaries.yml b/.github/workflows/binaries.yml index 7f7ec1da..e49e9f26 100644 --- a/.github/workflows/binaries.yml +++ b/.github/workflows/binaries.yml @@ -160,14 +160,6 @@ jobs: steps: - uses: actions/checkout@master - - name: Set version suffix - run: | - if [[ "${{ github.ref_type }}" == "tag" ]]; then - echo "VERSION_SUFFIX=${{ github.ref_name }}" >> $GITHUB_ENV - else - echo "VERSION_SUFFIX=$(git rev-parse --short HEAD)" >> $GITHUB_ENV - fi - - name: Download headers uses: actions/download-artifact@v4 with: @@ -178,6 +170,14 @@ jobs: with: install: gcc make curl zip + - name: Set version suffix + run: | + if [[ "${{ github.ref_type }}" == "tag" ]]; then + echo "VERSION_SUFFIX=${{ github.ref_name }}" >> $GITHUB_ENV + else + echo "VERSION_SUFFIX=$(git rev-parse --short HEAD)" >> $GITHUB_ENV + fi + - name: Show GCC run: gcc -v From 74e1e55cef028f7a1ef5dc80c116cea4cec45545 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 9 Jan 2026 17:13:26 -0800 Subject: [PATCH 509/554] see if this fixes windows archive name --- .github/workflows/binaries.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/binaries.yml b/.github/workflows/binaries.yml index e49e9f26..b0324230 100644 --- a/.github/workflows/binaries.yml +++ b/.github/workflows/binaries.yml @@ -171,6 +171,7 @@ jobs: install: gcc make curl zip - name: Set version suffix + shell: bash run: | if [[ "${{ github.ref_type }}" == "tag" ]]; then echo "VERSION_SUFFIX=${{ github.ref_name }}" >> $GITHUB_ENV From 5164ab0be9145edf142cb49f88e58edf87914f10 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 26 Feb 2026 15:20:55 -0800 Subject: [PATCH 510/554] add is_instance and is_object to moon library --- docs/standard_lib.md | 41 +++++++++++++++++-- moon/init.lua | 18 +++++++-- moon/init.moon | 16 ++++++-- moonscript/util.lua | 13 ++++-- moonscript/util.moon | 16 ++++++-- spec/moon_spec.moon | 95 +++++++++++++++++++++++++++++++++++++++----- 6 files changed, 173 insertions(+), 26 deletions(-) diff --git a/docs/standard_lib.md b/docs/standard_lib.md index 3a86a7b8..9042fb3f 100644 --- a/docs/standard_lib.md +++ b/docs/standard_lib.md @@ -108,19 +108,52 @@ copy = (arg) -> {k,v for k,v in pairs self} ### `is_object(value)` -Returns true if `value` is an instance of a MoonScript class, false otherwise. +**Deprecated:** Use `is_instance` or `is_class` instead. `is_object` returns +truthy for instances, classes, and `__base` tables — any table with `__class` +accessible. It cannot distinguish between these cases. + +### `is_class(value)` + +Returns `true` if `value` is a MoonScript class table, `false` otherwise. +Returns `false` for instances, `__base` tables, plain tables, and non-table +values. + +```moon +class MyClass + +is_class MyClass -- true +is_class MyClass! -- false +is_class MyClass.__base -- false +``` + +### `is_instance(value)` + +Returns `true` if `value` is an instance of a MoonScript class, `false` +otherwise. Returns `false` for class tables, `__base` tables, plain tables, and +non-table values. + +```moon +class MyClass + +is_instance MyClass! -- true +is_instance MyClass -- false +is_instance MyClass.__base -- false +``` ### `type(value)` -If `value` is an instance of a MoonScript class, then return it's class object. -Otherwise, return the result of calling Lua's type method. +If `value` is an instance of a MoonScript class, then return its class object. +If `value` is a class table, return the class itself. Returns the result of +calling Lua's built-in `type` for all other values, including `__base` tables +and plain tables. ```moon class MyClass - nil x = MyClass! assert type(x) == MyClass +assert type(MyClass) == MyClass +assert type(MyClass.__base) == "table" ``` ### `bind_methods(obj)` diff --git a/moon/init.lua b/moon/init.lua index 52ead55d..d2993a0a 100644 --- a/moon/init.lua +++ b/moon/init.lua @@ -7,21 +7,31 @@ do local _obj_0 = require("moonscript.util") getfenv, setfenv, dump = _obj_0.getfenv, _obj_0.setfenv, _obj_0.dump end -local p, is_object, type, debug, run_with_scope, bind_methods, defaultbl, extend, copy, mixin, mixin_object, mixin_table, fold +local p, is_object, is_class, is_instance, type, debug, run_with_scope, bind_methods, defaultbl, extend, copy, mixin, mixin_object, mixin_table, fold p = function(o, ...) print(dump(o)) if select("#", ...) > 0 then return p(...) end end -is_object = function(value) +is_object = function(value) -- deprecated: use is_instance or is_class instead return lua.type(value) == "table" and value.__class end +is_class = function(value) + return lua.type(value) == "table" and rawget(value, "__base") ~= nil +end +is_instance = function(value) + if lua.type(value) == "table" then + local mt = getmetatable(value) + return mt and rawget(mt, "__class") ~= nil + end + return false +end type = function(value) local base_type = lua.type(value) if base_type == "table" then local cls = value.__class - if cls then + if cls and rawget(value, "__class") == nil then return cls end end @@ -164,6 +174,8 @@ return { dump = dump, p = p, is_object = is_object, + is_class = is_class, + is_instance = is_instance, type = type, debug = debug, run_with_scope = run_with_scope, diff --git a/moon/init.moon b/moon/init.moon index 57325eea..c7c0abd8 100644 --- a/moon/init.moon +++ b/moon/init.moon @@ -9,14 +9,24 @@ p = (o, ...) -> if select("#", ...) > 0 p ... -is_object = (value) -> -- is a moonscript object +is_object = (value) -> -- deprecated: use is_instance or is_class instead lua.type(value) == "table" and value.__class +is_class = (value) -> + lua.type(value) == "table" and rawget(value, "__base") != nil + +is_instance = (value) -> + if lua.type(value) == "table" + mt = getmetatable value + return mt and rawget(mt, "__class") != nil + false + type = (value) -> -- class aware type base_type = lua.type value if base_type == "table" cls = value.__class - return cls if cls + if cls and rawget(value, "__class") == nil + return cls base_type debug = setmetatable { @@ -130,6 +140,6 @@ fold = (items, fn)-> items[1] { - :dump, :p, :is_object, :type, :debug, :run_with_scope, :bind_methods, + :dump, :p, :is_object, :is_class, :is_instance, :type, :debug, :run_with_scope, :bind_methods, :defaultbl, :extend, :copy, :mixin, :mixin_object, :mixin_table, :fold } diff --git a/moonscript/util.lua b/moonscript/util.lua index 83d7e37f..c8a9f911 100644 --- a/moonscript/util.lua +++ b/moonscript/util.lua @@ -3,8 +3,15 @@ concat = table.concat local unpack = unpack or table.unpack local type = type local moon = { - is_object = function(value) - return type(value) == "table" and value.__class + is_class = function(value) + return type(value) == "table" and rawget(value, "__base") ~= nil + end, + is_instance = function(value) + if type(value) == "table" then + local mt = getmetatable(value) + return mt and rawget(mt, "__class") ~= nil + end + return false end, is_a = function(thing, t) if not (type(thing) == "table") then @@ -23,7 +30,7 @@ local moon = { local base_type = type(value) if base_type == "table" then local cls = value.__class - if cls then + if cls and rawget(value, "__class") == nil then return cls end end diff --git a/moonscript/util.moon b/moonscript/util.moon index 9969ac4a..60bfee53 100644 --- a/moonscript/util.moon +++ b/moonscript/util.moon @@ -4,9 +4,15 @@ import concat from table unpack = unpack or table.unpack type = type -moon = - is_object: (value) -> -- is a moonscript object - type(value) == "table" and value.__class +moon = { + is_class: (value) -> + type(value) == "table" and rawget(value, "__base") != nil + + is_instance: (value) -> + if type(value) == "table" + mt = getmetatable value + return mt and rawget(mt, "__class") != nil + false is_a: (thing, t) -> return false unless type(thing) == "table" @@ -22,8 +28,10 @@ moon = base_type = type value if base_type == "table" cls = value.__class - return cls if cls + if cls and rawget(value, "__class") == nil + return cls base_type +} -- convet position in text to line number pos_to_line = (str, pos) -> diff --git a/spec/moon_spec.moon b/spec/moon_spec.moon index 773e53c0..61694470 100644 --- a/spec/moon_spec.moon +++ b/spec/moon_spec.moon @@ -8,15 +8,37 @@ describe "moon", -> with_dev -> moon = require "moon" - it "should determine correct type", -> - class Test - - things = { - Test, Test!, 1, true, nil, "hello" - } - - types = [moon.type t for t in *things] - assert.same types, { Test, Test, "number", "boolean", "nil", "string" } + describe "type", -> + it "returns the class for a class", -> + class Test + assert.equal Test, moon.type Test + + it "returns the class for an instance", -> + class Test + assert.equal Test, moon.type Test! + + it "returns 'table' for __base", -> + class Test + assert.equal "table", moon.type Test.__base + + it "returns primitive type for non-tables", -> + assert.equal "number", moon.type 1 + assert.equal "boolean", moon.type true + assert.equal "nil", moon.type nil + assert.equal "string", moon.type "hello" + assert.equal "function", moon.type -> + + it "returns 'table' for plain tables", -> + assert.equal "table", moon.type {} + assert.equal "table", moon.type {hello: "world"} + + it "works with inheritance", -> + class Parent + class Child extends Parent + assert.equal Child, moon.type Child! + assert.equal Parent, moon.type Parent! + assert.equal "table", moon.type Child.__base + assert.equal "table", moon.type Parent.__base it "should get upvalue", -> fn = do @@ -114,6 +136,61 @@ describe "moon", -> assert.same a, { hello: "world", cat: "mouse", foo: "bar"} + describe "is_class", -> + it "returns true for a class", -> + class Hello + assert.truthy moon.is_class Hello + + it "returns false for an instance", -> + class Hello + assert.falsy moon.is_class Hello! + + it "returns false for __base", -> + class Hello + assert.falsy moon.is_class Hello.__base + + it "returns false for plain tables and non-tables", -> + assert.falsy moon.is_class {} + assert.falsy moon.is_class 123 + assert.falsy moon.is_class "hello" + assert.falsy moon.is_class nil + assert.falsy moon.is_class true + + it "works with inheritance", -> + class Parent + class Child extends Parent + assert.truthy moon.is_class Parent + assert.truthy moon.is_class Child + assert.falsy moon.is_class Child! + + describe "is_instance", -> + it "returns true for an instance", -> + class Hello + assert.truthy moon.is_instance Hello! + + it "returns false for a class", -> + class Hello + assert.falsy moon.is_instance Hello + + it "returns false for __base", -> + class Hello + assert.falsy moon.is_instance Hello.__base + + it "returns false for plain tables and non-tables", -> + assert.falsy moon.is_instance {} + assert.falsy moon.is_instance 123 + assert.falsy moon.is_instance "hello" + assert.falsy moon.is_instance nil + assert.falsy moon.is_instance true + + it "works with inheritance", -> + class Parent + class Child extends Parent + assert.truthy moon.is_instance Parent! + assert.truthy moon.is_instance Child! + assert.falsy moon.is_instance Parent + assert.falsy moon.is_instance Child + it "should fold", -> numbers = {4,3,5,6,7,2,3} sum = moon.fold numbers, (a,b) -> a + b From 898a31159fad07717d45e65d53da095063f828ae Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 26 Feb 2026 15:53:08 -0800 Subject: [PATCH 511/554] tweak the is_instance and is_class functions, add more tests --- docs/standard_lib.md | 8 +++++++ moon/init.lua | 10 +++++--- moon/init.moon | 7 ++++-- moonscript/util.lua | 8 +++++-- moonscript/util.moon | 7 ++++-- spec/moon_spec.moon | 54 ++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 85 insertions(+), 9 deletions(-) diff --git a/docs/standard_lib.md b/docs/standard_lib.md index 9042fb3f..56e6b88a 100644 --- a/docs/standard_lib.md +++ b/docs/standard_lib.md @@ -118,6 +118,10 @@ Returns `true` if `value` is a MoonScript class table, `false` otherwise. Returns `false` for instances, `__base` tables, plain tables, and non-table values. +Works by checking that the value is a table with a `__base` field set directly +on it, and that its metatable has a `__call` field (the constructor). Both are +properties unique to MoonScript class tables. + ```moon class MyClass @@ -132,6 +136,10 @@ Returns `true` if `value` is an instance of a MoonScript class, `false` otherwise. Returns `false` for class tables, `__base` tables, plain tables, and non-table values. +Works by checking that the value is a table whose metatable is a `__base` table +(identified by having a self-referencing `__index`), and that the value itself +is not a `__base` table. + ```moon class MyClass diff --git a/moon/init.lua b/moon/init.lua index d2993a0a..82047f85 100644 --- a/moon/init.lua +++ b/moon/init.lua @@ -14,16 +14,20 @@ p = function(o, ...) return p(...) end end -is_object = function(value) -- deprecated: use is_instance or is_class instead +is_object = function(value) return lua.type(value) == "table" and value.__class end is_class = function(value) - return lua.type(value) == "table" and rawget(value, "__base") ~= nil + if lua.type(value) == "table" and rawget(value, "__base") ~= nil then + local mt = getmetatable(value) + return mt and rawget(mt, "__call") ~= nil + end + return false end is_instance = function(value) if lua.type(value) == "table" then local mt = getmetatable(value) - return mt and rawget(mt, "__class") ~= nil + return mt and rawget(mt, "__index") == mt and rawget(value, "__index") ~= value end return false end diff --git a/moon/init.moon b/moon/init.moon index c7c0abd8..f85d40ee 100644 --- a/moon/init.moon +++ b/moon/init.moon @@ -13,12 +13,15 @@ is_object = (value) -> -- deprecated: use is_instance or is_class instead lua.type(value) == "table" and value.__class is_class = (value) -> - lua.type(value) == "table" and rawget(value, "__base") != nil + if lua.type(value) == "table" and rawget(value, "__base") != nil + mt = getmetatable value + return mt and rawget(mt, "__call") != nil + false is_instance = (value) -> if lua.type(value) == "table" mt = getmetatable value - return mt and rawget(mt, "__class") != nil + return mt and rawget(mt, "__index") == mt and rawget(value, "__index") != value false type = (value) -> -- class aware type diff --git a/moonscript/util.lua b/moonscript/util.lua index c8a9f911..9dc77d6d 100644 --- a/moonscript/util.lua +++ b/moonscript/util.lua @@ -4,12 +4,16 @@ local unpack = unpack or table.unpack local type = type local moon = { is_class = function(value) - return type(value) == "table" and rawget(value, "__base") ~= nil + if type(value) == "table" and rawget(value, "__base") ~= nil then + local mt = getmetatable(value) + return mt and rawget(mt, "__call") ~= nil + end + return false end, is_instance = function(value) if type(value) == "table" then local mt = getmetatable(value) - return mt and rawget(mt, "__class") ~= nil + return mt and rawget(mt, "__index") == mt and rawget(value, "__index") ~= value end return false end, diff --git a/moonscript/util.moon b/moonscript/util.moon index 60bfee53..e2b67799 100644 --- a/moonscript/util.moon +++ b/moonscript/util.moon @@ -6,12 +6,15 @@ type = type moon = { is_class: (value) -> - type(value) == "table" and rawget(value, "__base") != nil + if type(value) == "table" and rawget(value, "__base") != nil + mt = getmetatable value + return mt and rawget(mt, "__call") != nil + false is_instance: (value) -> if type(value) == "table" mt = getmetatable value - return mt and rawget(mt, "__class") != nil + return mt and rawget(mt, "__index") == mt and rawget(value, "__index") != value false is_a: (thing, t) -> diff --git a/spec/moon_spec.moon b/spec/moon_spec.moon index 61694470..3e87ca1d 100644 --- a/spec/moon_spec.moon +++ b/spec/moon_spec.moon @@ -21,6 +21,12 @@ describe "moon", -> class Test assert.equal "table", moon.type Test.__base + it "returns 'table' for __base with inheritance", -> + class Parent + class Child extends Parent + assert.equal "table", moon.type Child.__base + assert.equal "table", moon.type Parent.__base + it "returns primitive type for non-tables", -> assert.equal "number", moon.type 1 assert.equal "boolean", moon.type true @@ -149,6 +155,12 @@ describe "moon", -> class Hello assert.falsy moon.is_class Hello.__base + it "returns false for __base with inheritance", -> + class Parent + class Child extends Parent + assert.falsy moon.is_class Child.__base + assert.falsy moon.is_class Parent.__base + it "returns false for plain tables and non-tables", -> assert.falsy moon.is_class {} assert.falsy moon.is_class 123 @@ -163,6 +175,42 @@ describe "moon", -> assert.truthy moon.is_class Child assert.falsy moon.is_class Child! + describe "is_instance and is_class with imposter tables", -> + it "rejects table with only __base set", -> + fake = { __base: {} } + assert.falsy moon.is_class fake + assert.falsy moon.is_instance fake + + it "rejects table with __base and non-callable metatable", -> + fake = setmetatable { __base: {} }, { __index: {} } + assert.falsy moon.is_class fake + assert.falsy moon.is_instance fake + + it "rejects table with self-referencing __index but no metatable", -> + fake = {} + fake.__index = fake + assert.falsy moon.is_class fake + assert.falsy moon.is_instance fake + + it "rejects table with __class set directly", -> + fake = { __class: {} } + assert.falsy moon.is_class fake + assert.falsy moon.is_instance fake + + it "rejects table whose metatable has __class but not self-referencing __index", -> + mt = { __class: {} } + fake = setmetatable {}, mt + assert.falsy moon.is_class fake + assert.falsy moon.is_instance fake + + it "rejects table with self-referencing __index used as its own metatable", -> + -- looks like a __base used as a metatable for itself + fake = {} + fake.__index = fake + setmetatable fake, fake + assert.falsy moon.is_class fake + assert.falsy moon.is_instance fake + describe "is_instance", -> it "returns true for an instance", -> class Hello @@ -176,6 +224,12 @@ describe "moon", -> class Hello assert.falsy moon.is_instance Hello.__base + it "returns false for __base with inheritance", -> + class Parent + class Child extends Parent + assert.falsy moon.is_instance Child.__base + assert.falsy moon.is_instance Parent.__base + it "returns false for plain tables and non-tables", -> assert.falsy moon.is_instance {} assert.falsy moon.is_instance 123 From 9bff9ae77598451bf17491177ebd8ad82526c23c Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 26 Feb 2026 16:08:12 -0800 Subject: [PATCH 512/554] add is_instance_of public function --- docs/standard_lib.md | 17 ++++++++++++ moon/init.lua | 17 +++++++++++- moon/init.moon | 12 ++++++++- moonscript/util.lua | 13 ---------- moonscript/util.moon | 10 ------- spec/moon_spec.moon | 62 ++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 106 insertions(+), 25 deletions(-) diff --git a/docs/standard_lib.md b/docs/standard_lib.md index 56e6b88a..37b7b1e6 100644 --- a/docs/standard_lib.md +++ b/docs/standard_lib.md @@ -148,6 +148,23 @@ is_instance MyClass -- false is_instance MyClass.__base -- false ``` +### `is_instance_of(value, class)` + +Returns `true` if `value` is an instance of `class` or any of its parent +classes, `false` otherwise. Throws an error if `value` is not a MoonScript +instance. First verifies that `value` is a valid instance using `is_instance`, +then walks the `__parent` chain to check if the instance's class matches or +inherits from `class`. + +```moon +class Parent +class Child extends Parent + +is_instance_of Child!, Parent -- true +is_instance_of Child!, Child -- true +is_instance_of Parent!, Child -- false +``` + ### `type(value)` If `value` is an instance of a MoonScript class, then return its class object. diff --git a/moon/init.lua b/moon/init.lua index 82047f85..65b69c74 100644 --- a/moon/init.lua +++ b/moon/init.lua @@ -7,7 +7,7 @@ do local _obj_0 = require("moonscript.util") getfenv, setfenv, dump = _obj_0.getfenv, _obj_0.setfenv, _obj_0.dump end -local p, is_object, is_class, is_instance, type, debug, run_with_scope, bind_methods, defaultbl, extend, copy, mixin, mixin_object, mixin_table, fold +local p, is_object, is_class, is_instance, is_instance_of, type, debug, run_with_scope, bind_methods, defaultbl, extend, copy, mixin, mixin_object, mixin_table, fold p = function(o, ...) print(dump(o)) if select("#", ...) > 0 then @@ -31,6 +31,20 @@ is_instance = function(value) end return false end +is_instance_of = function(value, cls) + if not (is_instance(value)) then + error("is_instance_of: expected instance, got " .. tostring(lua.type(value))) + end + local mt = getmetatable(value) + local check = rawget(mt, "__class") + while check do + if check == cls then + return true + end + check = check.__parent + end + return false +end type = function(value) local base_type = lua.type(value) if base_type == "table" then @@ -180,6 +194,7 @@ return { is_object = is_object, is_class = is_class, is_instance = is_instance, + is_instance_of = is_instance_of, type = type, debug = debug, run_with_scope = run_with_scope, diff --git a/moon/init.moon b/moon/init.moon index f85d40ee..c2d5c8fc 100644 --- a/moon/init.moon +++ b/moon/init.moon @@ -24,6 +24,16 @@ is_instance = (value) -> return mt and rawget(mt, "__index") == mt and rawget(value, "__index") != value false +is_instance_of = (value, cls) -> + error "is_instance_of: expected instance, got #{lua.type value}" unless is_instance value + mt = getmetatable value + check = rawget mt, "__class" + while check + if check == cls + return true + check = check.__parent + false + type = (value) -> -- class aware type base_type = lua.type value if base_type == "table" @@ -143,6 +153,6 @@ fold = (items, fn)-> items[1] { - :dump, :p, :is_object, :is_class, :is_instance, :type, :debug, :run_with_scope, :bind_methods, + :dump, :p, :is_object, :is_class, :is_instance, :is_instance_of, :type, :debug, :run_with_scope, :bind_methods, :defaultbl, :extend, :copy, :mixin, :mixin_object, :mixin_table, :fold } diff --git a/moonscript/util.lua b/moonscript/util.lua index 9dc77d6d..3b5ea737 100644 --- a/moonscript/util.lua +++ b/moonscript/util.lua @@ -17,19 +17,6 @@ local moon = { end return false end, - is_a = function(thing, t) - if not (type(thing) == "table") then - return false - end - local cls = thing.__class - while cls do - if cls == t then - return true - end - cls = cls.__parent - end - return false - end, type = function(value) local base_type = type(value) if base_type == "table" then diff --git a/moonscript/util.moon b/moonscript/util.moon index e2b67799..5fde5c09 100644 --- a/moonscript/util.moon +++ b/moonscript/util.moon @@ -17,16 +17,6 @@ moon = { return mt and rawget(mt, "__index") == mt and rawget(value, "__index") != value false - is_a: (thing, t) -> - return false unless type(thing) == "table" - cls = thing.__class - while cls - if cls == t - return true - cls = cls.__parent - - false - type: (value) -> -- the moonscript object class base_type = type value if base_type == "table" diff --git a/spec/moon_spec.moon b/spec/moon_spec.moon index 3e87ca1d..ccfa6255 100644 --- a/spec/moon_spec.moon +++ b/spec/moon_spec.moon @@ -245,6 +245,68 @@ describe "moon", -> assert.falsy moon.is_instance Parent assert.falsy moon.is_instance Child + describe "is_instance_of", -> + it "returns true for direct instance", -> + class Hello + assert.truthy moon.is_instance_of Hello!, Hello + + it "returns true for instance of parent class", -> + class Parent + class Child extends Parent + assert.truthy moon.is_instance_of Child!, Parent + assert.truthy moon.is_instance_of Child!, Child + + it "returns false for instance of unrelated class", -> + class A + class B + assert.falsy moon.is_instance_of A!, B + assert.falsy moon.is_instance_of B!, A + + it "returns false for parent instance checked against child class", -> + class Parent + class Child extends Parent + assert.falsy moon.is_instance_of Parent!, Child + + it "errors when value is not an instance", -> + class Hello + assert.has_error (-> moon.is_instance_of Hello, Hello), "is_instance_of: expected instance, got table" + assert.has_error (-> moon.is_instance_of Hello.__base, Hello), "is_instance_of: expected instance, got table" + assert.has_error (-> moon.is_instance_of {}, Hello), "is_instance_of: expected instance, got table" + assert.has_error (-> moon.is_instance_of nil, Hello), "is_instance_of: expected instance, got nil" + assert.has_error (-> moon.is_instance_of 123, Hello), "is_instance_of: expected instance, got number" + + it "errors when __base is passed as the value", -> + class Parent + class Child extends Parent + assert.has_error (-> moon.is_instance_of Parent.__base, Parent), "is_instance_of: expected instance, got table" + assert.has_error (-> moon.is_instance_of Child.__base, Child), "is_instance_of: expected instance, got table" + assert.has_error (-> moon.is_instance_of Child.__base, Parent), "is_instance_of: expected instance, got table" + + it "returns false when __base is passed as the class", -> + class Parent + class Child extends Parent + assert.falsy moon.is_instance_of Parent!, Parent.__base + assert.falsy moon.is_instance_of Child!, Child.__base + assert.falsy moon.is_instance_of Child!, Parent.__base + + it "errors when __base is on both sides", -> + class Parent + class Child extends Parent + assert.has_error (-> moon.is_instance_of Parent.__base, Parent.__base), "is_instance_of: expected instance, got table" + assert.has_error (-> moon.is_instance_of Child.__base, Child.__base), "is_instance_of: expected instance, got table" + assert.has_error (-> moon.is_instance_of Child.__base, Parent.__base), "is_instance_of: expected instance, got table" + assert.has_error (-> moon.is_instance_of Parent.__base, Child.__base), "is_instance_of: expected instance, got table" + + it "works with deep inheritance chain", -> + class A + class B extends A + class C extends B + assert.truthy moon.is_instance_of C!, A + assert.truthy moon.is_instance_of C!, B + assert.truthy moon.is_instance_of C!, C + assert.falsy moon.is_instance_of A!, B + assert.falsy moon.is_instance_of A!, C + it "should fold", -> numbers = {4,3,5,6,7,2,3} sum = moon.fold numbers, (a,b) -> a + b From 980acd226bd3cb993790f5f03fcf3b678d0cf49a Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 26 Feb 2026 16:18:17 -0800 Subject: [PATCH 513/554] add is_subcalss_of, BREAKING: enhance moon.type() to remove weird class object behavior --- docs/standard_lib.md | 31 ++++++++++++++++----- moon/init.lua | 19 ++++++++++++- moon/init.moon | 13 ++++++++- spec/moon_spec.moon | 64 ++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 117 insertions(+), 10 deletions(-) diff --git a/docs/standard_lib.md b/docs/standard_lib.md index 37b7b1e6..f683e080 100644 --- a/docs/standard_lib.md +++ b/docs/standard_lib.md @@ -160,24 +160,43 @@ inherits from `class`. class Parent class Child extends Parent -is_instance_of Child!, Parent -- true is_instance_of Child!, Child -- true +is_instance_of Child!, Parent -- true (checks parent classes) is_instance_of Parent!, Child -- false ``` +To check if a value is a direct instance of a specific class without considering +inheritance, use `type(value) == MyClass` instead. + +### `is_subclass_of(cls, parent)` + +Returns `true` if `cls` is a subclass of `parent`, `false` otherwise. Throws an +error if `cls` is not a MoonScript class. Note that a class is not considered a +subclass of itself. Walks the `__parent` chain starting from `cls` to check if +any ancestor matches `parent`. + +```moon +class Parent +class Child extends Parent + +is_subclass_of Child, Parent -- true +is_subclass_of Parent, Child -- false +is_subclass_of Child, Child -- false +``` + ### `type(value)` -If `value` is an instance of a MoonScript class, then return its class object. -If `value` is a class table, return the class itself. Returns the result of -calling Lua's built-in `type` for all other values, including `__base` tables -and plain tables. +Returns a class-aware type for a value. If `value` is an instance of a +MoonScript class, returns its class object. If `value` is a class table, returns +the string `"class"`. Returns the result of calling Lua's built-in `type` for +all other values, including `__base` tables and plain tables. ```moon class MyClass x = MyClass! assert type(x) == MyClass -assert type(MyClass) == MyClass +assert type(MyClass) == "class" assert type(MyClass.__base) == "table" ``` diff --git a/moon/init.lua b/moon/init.lua index 65b69c74..52c17dfb 100644 --- a/moon/init.lua +++ b/moon/init.lua @@ -7,7 +7,7 @@ do local _obj_0 = require("moonscript.util") getfenv, setfenv, dump = _obj_0.getfenv, _obj_0.setfenv, _obj_0.dump end -local p, is_object, is_class, is_instance, is_instance_of, type, debug, run_with_scope, bind_methods, defaultbl, extend, copy, mixin, mixin_object, mixin_table, fold +local p, is_object, is_class, is_instance, is_instance_of, is_subclass_of, type, debug, run_with_scope, bind_methods, defaultbl, extend, copy, mixin, mixin_object, mixin_table, fold p = function(o, ...) print(dump(o)) if select("#", ...) > 0 then @@ -45,9 +45,25 @@ is_instance_of = function(value, cls) end return false end +is_subclass_of = function(cls, parent) + if not (is_class(cls)) then + error("is_subclass_of: expected class, got " .. tostring(lua.type(cls))) + end + local check = cls.__parent + while check do + if check == parent then + return true + end + check = check.__parent + end + return false +end type = function(value) local base_type = lua.type(value) if base_type == "table" then + if is_class(value) then + return "class" + end local cls = value.__class if cls and rawget(value, "__class") == nil then return cls @@ -195,6 +211,7 @@ return { is_class = is_class, is_instance = is_instance, is_instance_of = is_instance_of, + is_subclass_of = is_subclass_of, type = type, debug = debug, run_with_scope = run_with_scope, diff --git a/moon/init.moon b/moon/init.moon index c2d5c8fc..140194a2 100644 --- a/moon/init.moon +++ b/moon/init.moon @@ -34,9 +34,20 @@ is_instance_of = (value, cls) -> check = check.__parent false +is_subclass_of = (cls, parent) -> + error "is_subclass_of: expected class, got #{lua.type cls}" unless is_class cls + check = cls.__parent + while check + if check == parent + return true + check = check.__parent + false + type = (value) -> -- class aware type base_type = lua.type value if base_type == "table" + if is_class value + return "class" cls = value.__class if cls and rawget(value, "__class") == nil return cls @@ -153,6 +164,6 @@ fold = (items, fn)-> items[1] { - :dump, :p, :is_object, :is_class, :is_instance, :is_instance_of, :type, :debug, :run_with_scope, :bind_methods, + :dump, :p, :is_object, :is_class, :is_instance, :is_instance_of, :is_subclass_of, :type, :debug, :run_with_scope, :bind_methods, :defaultbl, :extend, :copy, :mixin, :mixin_object, :mixin_table, :fold } diff --git a/spec/moon_spec.moon b/spec/moon_spec.moon index ccfa6255..e43c22b7 100644 --- a/spec/moon_spec.moon +++ b/spec/moon_spec.moon @@ -9,9 +9,9 @@ describe "moon", -> moon = require "moon" describe "type", -> - it "returns the class for a class", -> + it "returns 'class' for a class", -> class Test - assert.equal Test, moon.type Test + assert.equal "class", moon.type Test it "returns the class for an instance", -> class Test @@ -38,6 +38,12 @@ describe "moon", -> assert.equal "table", moon.type {} assert.equal "table", moon.type {hello: "world"} + it "returns 'class' for classes with inheritance", -> + class Parent + class Child extends Parent + assert.equal "class", moon.type Parent + assert.equal "class", moon.type Child + it "works with inheritance", -> class Parent class Child extends Parent @@ -307,6 +313,60 @@ describe "moon", -> assert.falsy moon.is_instance_of A!, B assert.falsy moon.is_instance_of A!, C + describe "is_subclass_of", -> + it "returns true for direct child", -> + class Parent + class Child extends Parent + assert.truthy moon.is_subclass_of Child, Parent + + it "returns true for deep inheritance", -> + class A + class B extends A + class C extends B + assert.truthy moon.is_subclass_of C, A + assert.truthy moon.is_subclass_of C, B + assert.truthy moon.is_subclass_of B, A + + it "returns false for same class", -> + class A + assert.falsy moon.is_subclass_of A, A + + it "returns false for parent checked against child", -> + class Parent + class Child extends Parent + assert.falsy moon.is_subclass_of Parent, Child + + it "returns false for unrelated classes", -> + class A + class B + assert.falsy moon.is_subclass_of A, B + assert.falsy moon.is_subclass_of B, A + + it "returns false for class without parent", -> + class A + class B + assert.falsy moon.is_subclass_of A, B + + it "returns false when __base is passed as the parent", -> + class Parent + class Child extends Parent + assert.falsy moon.is_subclass_of Child, Parent.__base + assert.falsy moon.is_subclass_of Child, Child.__base + + it "errors when first argument is not a class", -> + class Hello + assert.has_error (-> moon.is_subclass_of Hello!, Hello), "is_subclass_of: expected class, got table" + assert.has_error (-> moon.is_subclass_of Hello.__base, Hello), "is_subclass_of: expected class, got table" + assert.has_error (-> moon.is_subclass_of {}, Hello), "is_subclass_of: expected class, got table" + assert.has_error (-> moon.is_subclass_of nil, Hello), "is_subclass_of: expected class, got nil" + assert.has_error (-> moon.is_subclass_of 123, Hello), "is_subclass_of: expected class, got number" + + it "errors when __base is passed as the first argument", -> + class Parent + class Child extends Parent + assert.has_error (-> moon.is_subclass_of Parent.__base, Parent), "is_subclass_of: expected class, got table" + assert.has_error (-> moon.is_subclass_of Child.__base, Child), "is_subclass_of: expected class, got table" + it "should fold", -> numbers = {4,3,5,6,7,2,3} sum = moon.fold numbers, (a,b) -> a + b From 06191f0dffb75a40b0fdc195378761b363413e1e Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 26 Feb 2026 16:22:32 -0800 Subject: [PATCH 514/554] update moonscript.util moon.mtype -> mtype to differentiate between the type function in moon --- moonscript/cmd/lint.lua | 2 +- moonscript/cmd/lint.moon | 2 +- moonscript/compile.lua | 5 ++--- moonscript/compile.moon | 4 +--- moonscript/types.lua | 2 +- moonscript/types.moon | 2 +- moonscript/util.lua | 22 ++++++++++++---------- moonscript/util.moon | 17 +++++++++-------- 8 files changed, 28 insertions(+), 28 deletions(-) diff --git a/moonscript/cmd/lint.lua b/moonscript/cmd/lint.lua index 68053ca5..67805253 100644 --- a/moonscript/cmd/lint.lua +++ b/moonscript/cmd/lint.lua @@ -5,7 +5,7 @@ Set = require("moonscript.data").Set local Block Block = require("moonscript.compile").Block local mtype -mtype = require("moonscript.util").moon.type +mtype = require("moonscript.util").mtype local default_whitelist = Set({ '_G', '_VERSION', diff --git a/moonscript/cmd/lint.moon b/moonscript/cmd/lint.moon index 103c25ed..043eb2cf 100644 --- a/moonscript/cmd/lint.moon +++ b/moonscript/cmd/lint.moon @@ -3,7 +3,7 @@ import insert from table import Set from require "moonscript.data" import Block from require "moonscript.compile" -{type: mtype} = require("moonscript.util").moon +import mtype from require "moonscript.util" -- globals allowed to be referenced default_whitelist = Set { diff --git a/moonscript/compile.lua b/moonscript/compile.lua index 66f4df59..2eb4df16 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -20,9 +20,8 @@ do local _obj_0 = table concat, insert = _obj_0.concat, _obj_0.insert end -local pos_to_line, get_closest_line, trim, unpack -pos_to_line, get_closest_line, trim, unpack = util.pos_to_line, util.get_closest_line, util.trim, util.unpack -local mtype = util.moon.type +local pos_to_line, get_closest_line, trim, unpack, mtype +pos_to_line, get_closest_line, trim, unpack, mtype = util.pos_to_line, util.get_closest_line, util.trim, util.unpack, util.mtype local indent_char = " " local Line, DelayedLine, Lines, Block, RootBlock do diff --git a/moonscript/compile.moon b/moonscript/compile.moon index 716c2c4e..e6cf00a6 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -11,9 +11,7 @@ statement_compilers = require "moonscript.compile.statement" value_compilers = require "moonscript.compile.value" import concat, insert from table -import pos_to_line, get_closest_line, trim, unpack from util - -mtype = util.moon.type +import pos_to_line, get_closest_line, trim, unpack, mtype from util indent_char = " " diff --git a/moonscript/types.lua b/moonscript/types.lua index e8efc409..0f3a6907 100644 --- a/moonscript/types.lua +++ b/moonscript/types.lua @@ -36,7 +36,7 @@ ntype = function(node) end local mtype do - local moon_type = util.moon.type + local moon_type = util.mtype mtype = function(val) local mt = getmetatable(val) if mt and mt.smart_node then diff --git a/moonscript/types.moon b/moonscript/types.moon index 23f4ed91..d7288130 100644 --- a/moonscript/types.moon +++ b/moonscript/types.moon @@ -33,7 +33,7 @@ ntype = (node) -> -- gets the class of a type if possible mtype = do - moon_type = util.moon.type + moon_type = util.mtype -- lets us check a smart node without throwing an error (val) -> mt = getmetatable val diff --git a/moonscript/util.lua b/moonscript/util.lua index 3b5ea737..dbb1b437 100644 --- a/moonscript/util.lua +++ b/moonscript/util.lua @@ -16,18 +16,19 @@ local moon = { return mt and rawget(mt, "__index") == mt and rawget(value, "__index") ~= value end return false - end, - type = function(value) - local base_type = type(value) - if base_type == "table" then - local cls = value.__class - if cls and rawget(value, "__class") == nil then - return cls - end - end - return base_type end } +local mtype +mtype = function(value) + local base_type = type(value) + if base_type == "table" then + local cls = value.__class + if cls and rawget(value, "__class") == nil then + return cls + end + end + return base_type +end local pos_to_line pos_to_line = function(str, pos) local line = 1 @@ -200,6 +201,7 @@ safe_module = function(name, tbl) end return { moon = moon, + mtype = mtype, pos_to_line = pos_to_line, get_closest_line = get_closest_line, get_line = get_line, diff --git a/moonscript/util.moon b/moonscript/util.moon index 5fde5c09..492a72aa 100644 --- a/moonscript/util.moon +++ b/moonscript/util.moon @@ -17,15 +17,16 @@ moon = { return mt and rawget(mt, "__index") == mt and rawget(value, "__index") != value false - type: (value) -> -- the moonscript object class - base_type = type value - if base_type == "table" - cls = value.__class - if cls and rawget(value, "__class") == nil - return cls - base_type } +mtype = (value) -> -- the moonscript object class + base_type = type value + if base_type == "table" + cls = value.__class + if cls and rawget(value, "__class") == nil + return cls + base_type + -- convet position in text to line number pos_to_line = (str, pos) -> line = 1 @@ -135,7 +136,7 @@ safe_module = (name, tbl) -> } { - :moon, :pos_to_line, :get_closest_line, :get_line, :trim, :split, :dump, + :moon, :mtype, :pos_to_line, :get_closest_line, :get_line, :trim, :split, :dump, :debug_posmap, :getfenv, :setfenv, :get_options, :unpack, :safe_module } From e08e943aa178e7301bbdf3d9db74e70efe9e5ede Mon Sep 17 00:00:00 2001 From: Michel Lind Date: Fri, 27 Feb 2026 00:23:41 +0000 Subject: [PATCH 515/554] Update CHANGELOG.md (#469) The release notes for 0.6.0 is only available via the GitHub release page; add this to the changelog Resolves: #468 Signed-off-by: Michel Lind --- CHANGELOG.md | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dd9c43dc..e8a9f137 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,58 @@ +# MoonScript v0.6.0 (2026-01-10) + +## New Features + +### Command Line Improvements + +- **Switched from alt_getopt to argparse** - Both `moon` and `moonc` now use argparse for argument parsing, providing better help messages via `--help` and more robust option handling +- **Added `-e/--execute` flag to `moon`** - Execute MoonScript code directly from the command line: + ``` + moon -e "print 'Hello World'" + ``` +- **New `--transform` option for `moonc`** - Allows custom AST transformations before compilation by specifying a module that receives and returns the syntax tree +- **Improved `-` (stdin) handling** - Now properly enforces that `-` must be the only argument + +### moonc Option Renames +- `-w` is now also available as `--watch` +- `-l` is now also available as `--lint` +- `-t` is now also available as `--output-to` + +### New Tools + +- **moon-tags** - New script for generating ctags-compatible tag files for MoonScript, with support for: + - Class definitions + - Class methods + - Top-level function definitions (exported via `{:func}` pattern) + - Lapis route detection (`--lapis` flag) + - Optional line numbers (`--include-line` flag) + - Optionally skip header (`--no-header` flag) + +### Utility Improvements + +- **`moon.p()` now prints multiple arguments** - Pass multiple values and each will be dumped +- **`util.dump` shows class names** - When dumping objects, the class name is displayed (e.g., `{...}`) + +### Compiler Enhancements + +- **Lua keyword property access on self** - Properties with Lua keyword names (like `@then` or `@@then`) now compile correctly using bracket notation instead of invalid `self.then` + +## Bug Fixes + +- **Fixed ambiguous Lua generation after `import`** - Semicolons are now correctly inserted when the next line starts with `(`, preventing parsing ambiguity +- **Fixed update operators with complex chain indexes** - Expressions like `a[func()].x += 1` now correctly lift the index expression to avoid double evaluation +- **Exit with proper error code** - `moon` now exits with code 1 when the executed script fails +- **Fixed `moonc -`** - Reading from stdin now works correctly +- **Removed accidental debug print** - Removed stray `print file, time` in watcher code +- **`dump.tree` returns string** - Now returns the string instead of printing directly +- **Removed noisy "Built" message** - Single file compilation no longer prints "Built" to stderr + +## Internal Changes + +- Migrated CI from Travis to GitHub Actions +- Added comprehensive compiler and transform specs +- Improved binary building workflow for Windows and Linux +- Better error messages for invalid destructure assignments +- Updated `splat.moon` to use argparse, added `--strip-prefix` option # MoonScript v0.5.0 (2016-9-25) From 7b7899741c6c1e971e436d36c9aabb56f51dc3d5 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 26 Feb 2026 16:49:11 -0800 Subject: [PATCH 516/554] move this down --- docs/standard_lib.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/docs/standard_lib.md b/docs/standard_lib.md index f683e080..4a7c2dfa 100644 --- a/docs/standard_lib.md +++ b/docs/standard_lib.md @@ -106,11 +106,6 @@ copy = (arg) -> {k,v for k,v in pairs self} ## Class/Object Functions -### `is_object(value)` - -**Deprecated:** Use `is_instance` or `is_class` instead. `is_object` returns -truthy for instances, classes, and `__base` tables — any table with `__class` -accessible. It cannot distinguish between these cases. ### `is_class(value)` @@ -200,6 +195,14 @@ assert type(MyClass) == "class" assert type(MyClass.__base) == "table" ``` +### `is_object(value)` + +Legacy method for testing if a value is an instance. + +**Deprecated:** Use `is_instance` or `is_class` instead. `is_object` returns +truthy for instances, classes, and `__base` tables, any table with `__class` +accessible. It cannot distinguish between these cases. + ### `bind_methods(obj)` Takes an instance of an object, returns a proxy to the object whose methods can From 402be8a6df8ff57c4183db44e0c130d14d69bf87 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Wed, 27 May 2026 23:40:16 -0700 Subject: [PATCH 517/554] forgot to update the version --- moonscript/version.lua | 2 +- moonscript/version.moon | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/moonscript/version.lua b/moonscript/version.lua index 91f885aa..715b8291 100644 --- a/moonscript/version.lua +++ b/moonscript/version.lua @@ -1,4 +1,4 @@ -local version = "0.5.0" +local version = "0.6.0" return { version = version, print_version = function() diff --git a/moonscript/version.moon b/moonscript/version.moon index 68c483e4..931665cb 100644 --- a/moonscript/version.moon +++ b/moonscript/version.moon @@ -1,5 +1,5 @@ -version = "0.5.0" +version = "0.6.0" { version: version, From 1b591f7ac2b1d06eaa29a27e942e69fca552ea35 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 23 Jul 2026 09:41:05 -0700 Subject: [PATCH 518/554] add linux arm64 --- .github/workflows/binaries.yml | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/.github/workflows/binaries.yml b/.github/workflows/binaries.yml index b0324230..d165ae1d 100644 --- a/.github/workflows/binaries.yml +++ b/.github/workflows/binaries.yml @@ -47,12 +47,20 @@ jobs: path: bin/binaries/*.h linux: - runs-on: ubuntu-latest + runs-on: ${{ matrix.runner }} needs: generate-headers strategy: matrix: - lua_version: ["5.1.5"] + include: + - runner: ubuntu-latest + architecture: x86_64 + artifact_suffix: "" + lua_version: "5.1.5" + - runner: ubuntu-24.04-arm + architecture: arm64 + artifact_suffix: "-arm64" + lua_version: "5.1.5" steps: - uses: actions/checkout@master @@ -130,20 +138,20 @@ jobs: - name: Upload artifact uses: actions/upload-artifact@v6 with: - name: moonscript-${{ env.VERSION_SUFFIX }}-linux-lua${{ matrix.lua_version }} + name: moonscript-${{ env.VERSION_SUFFIX }}-linux-lua${{ matrix.lua_version }}${{ matrix.artifact_suffix }} path: dist/ - name: Package for release if: github.ref_type == 'tag' run: | cd dist - tar -czvf ../moonscript-${{ env.VERSION_SUFFIX }}-linux-x86_64.tar.gz * + tar -czvf ../moonscript-${{ env.VERSION_SUFFIX }}-linux-${{ matrix.architecture }}.tar.gz * - name: Upload to release if: github.ref_type == 'tag' uses: softprops/action-gh-release@v2 with: - files: moonscript-${{ env.VERSION_SUFFIX }}-linux-x86_64.tar.gz + files: moonscript-${{ env.VERSION_SUFFIX }}-linux-${{ matrix.architecture }}.tar.gz windows: runs-on: windows-latest From 68a9f38efcfe73d186a2f0bce5e830db968129bc Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 23 Jul 2026 09:56:28 -0700 Subject: [PATCH 519/554] opt into the new mooonscript parser --- moonscript/parse.lua | 21 ++++++++++++++++++++- moonscript/parse.moon | 19 ++++++++++++++++++- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/moonscript/parse.lua b/moonscript/parse.lua index da6731e7..5dd1540d 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -236,10 +236,29 @@ file_parser = function() end } end +local native_parser +local get_native_parser +get_native_parser = function() + if native_parser == nil then + if os.getenv("MOONSCRIPT_PARSER") == "pgen" then + native_parser = require("moonscript_parser") + else + native_parser = false + end + end + return native_parser +end return { extract_line = extract_line, build_grammar = build_grammar, string = function(str) - return file_parser():match(str) + do + local native = get_native_parser() + if native then + return native.string(str) + else + return file_parser():match(str) + end + end end } diff --git a/moonscript/parse.moon b/moonscript/parse.moon index 7fd5de6f..a556ce3c 100644 --- a/moonscript/parse.moon +++ b/moonscript/parse.moon @@ -350,12 +350,29 @@ file_parser = -> tree } +-- opt in to the compiled parser from the moonscript-parser rock by setting +-- MOONSCRIPT_PARSER=pgen in the environment. Fails loudly if the rock +-- isn't installed rather than silently using the LPeg parser +local native_parser +get_native_parser = -> + if native_parser == nil + native_parser = if os.getenv("MOONSCRIPT_PARSER") == "pgen" + require "moonscript_parser" + else + false + + native_parser + { :extract_line :build_grammar -- parse a string as a file -- returns tree, or nil and error message - string: (str) -> file_parser!\match str + string: (str) -> + if native = get_native_parser! + native.string str + else + file_parser!\match str } From 78fd8c988277fed82bbad0ce12689e474ab3f4a5 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 23 Jul 2026 09:59:31 -0700 Subject: [PATCH 520/554] fix version printout on moonc, fixes #471 --- bin/moonc | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/bin/moonc b/bin/moonc index 44f412dd..13e101af 100644 --- a/bin/moonc +++ b/bin/moonc @@ -7,7 +7,10 @@ local parser = argparse() parser:flag("-l --lint", "Perform a lint on the file instead of compiling") -parser:flag("-v --version", "Print version") +parser:flag("-v --version", "Print version"):action(function() + require("moonscript.version").print_version() + os.exit(0) +end) parser:flag("-w --watch", "Watch file/directory for updates") parser:option("--transform", "Transform syntax tree with module") @@ -36,12 +39,6 @@ end local opts = read_stdin and {} or parser:parse() -if opts.version then - local v = require "moonscript.version" - v.print_version() - os.exit() -end - function log_msg(...) if not opts.p then io.stderr:write(table.concat({...}, " ") .. "\n") From c077b3f3ca9bfd0b5b71c85bb6defd223d007262 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 24 Jul 2026 08:30:12 -0700 Subject: [PATCH 521/554] fix num_names bug (causes name list to get truncated) --- moonscript/transform/statement.lua | 2 +- moonscript/transform/statement.moon | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/moonscript/transform/statement.lua b/moonscript/transform/statement.lua index edeab697..e46ce23f 100644 --- a/moonscript/transform/statement.lua +++ b/moonscript/transform/statement.lua @@ -234,7 +234,7 @@ return Transformer({ assign = function(self, node) local names, values = unpack(node, 2) local num_values = #values - local num_names = #values + local num_names = #names if num_names == 1 and num_values == 1 then local first_value = values[1] local first_name = names[1] diff --git a/moonscript/transform/statement.moon b/moonscript/transform/statement.moon index 2e4b8e83..aa834b1a 100644 --- a/moonscript/transform/statement.moon +++ b/moonscript/transform/statement.moon @@ -136,7 +136,7 @@ Transformer { names, values = unpack node, 2 num_values = #values - num_names = #values + num_names = #names -- special code simplifications for single assigns if num_names == 1 and num_values == 1 From e979ba07789889d63b40273adf0afbaa1ad755a1 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 24 Jul 2026 08:31:10 -0700 Subject: [PATCH 522/554] make luajit binaries in ci --- .github/workflows/binaries.yml | 101 +++++++++++++++++++++++++++------ 1 file changed, 85 insertions(+), 16 deletions(-) diff --git a/.github/workflows/binaries.yml b/.github/workflows/binaries.yml index d165ae1d..f18cabd4 100644 --- a/.github/workflows/binaries.yml +++ b/.github/workflows/binaries.yml @@ -2,6 +2,10 @@ name: "binaries" on: [push] +env: + # LuaJIT has no releases; pin a commit from the v2.1 branch + LUAJIT_COMMIT: 346ab587cb235b4ef0b5777b4cd29009808d0cc0 + jobs: generate-headers: runs-on: ubuntu-latest @@ -56,11 +60,37 @@ jobs: - runner: ubuntu-latest architecture: x86_64 artifact_suffix: "" + runtime: puc lua_version: "5.1.5" + runtime_label: "lua5.1.5" + release_suffix: "" + lua_include: lua-5.1.5/src + lua_lib: lua-5.1.5/src/liblua.a + - runner: ubuntu-latest + architecture: x86_64 + artifact_suffix: "" + runtime: luajit + runtime_label: "luajit2.1" + release_suffix: "-luajit" + lua_include: luajit/src + lua_lib: luajit/src/libluajit.a - runner: ubuntu-24.04-arm architecture: arm64 artifact_suffix: "-arm64" + runtime: puc lua_version: "5.1.5" + runtime_label: "lua5.1.5" + release_suffix: "" + lua_include: lua-5.1.5/src + lua_lib: lua-5.1.5/src/liblua.a + - runner: ubuntu-24.04-arm + architecture: arm64 + artifact_suffix: "-arm64" + runtime: luajit + runtime_label: "luajit2.1" + release_suffix: "-luajit" + lua_include: luajit/src + lua_lib: luajit/src/libluajit.a steps: - uses: actions/checkout@master @@ -83,11 +113,20 @@ jobs: run: gcc -v - name: Setup Lua + if: matrix.runtime == 'puc' run: | curl -L -O https://www.lua.org/ftp/lua-${{ matrix.lua_version }}.tar.gz tar -xzf lua-${{ matrix.lua_version }}.tar.gz cd lua-${{ matrix.lua_version }}/src && make liblua.a MYCFLAGS=-DLUA_USE_POSIX + - name: Setup LuaJIT + if: matrix.runtime == 'luajit' + run: | + curl -L -o luajit.tar.gz https://github.com/LuaJIT/LuaJIT/archive/$LUAJIT_COMMIT.tar.gz + tar -xzf luajit.tar.gz + mv LuaJIT-* luajit + make -C luajit/src -j$(nproc) amalg BUILDMODE=static + - name: Get LPeg run: | curl -L -o lpeg.tar.gz https://www.inf.puc-rio.br/~roberto/lpeg/lpeg-1.0.2.tar.gz @@ -102,7 +141,7 @@ jobs: run: | mkdir -p dist gcc -static -o dist/moon \ - -Ilua-${{ matrix.lua_version }}/src/ \ + -I${{ matrix.lua_include }} \ -Ilpeg-1.0.2/ \ -Ibin/binaries/ \ bin/binaries/moon.c \ @@ -112,10 +151,10 @@ jobs: lpeg-1.0.2/lptree.c \ lpeg-1.0.2/lpcode.c \ lpeg-1.0.2/lpprint.c \ - lua-${{ matrix.lua_version }}/src/liblua.a \ + ${{ matrix.lua_lib }} \ -lm -ldl gcc -static -o dist/moonc \ - -Ilua-${{ matrix.lua_version }}/src/ \ + -I${{ matrix.lua_include }} \ -Ilpeg-1.0.2/ \ -Ibin/binaries/ \ bin/binaries/moonc.c \ @@ -126,7 +165,7 @@ jobs: lpeg-1.0.2/lpcode.c \ lpeg-1.0.2/lpprint.c \ luafilesystem-1_8_0/src/lfs.c \ - lua-${{ matrix.lua_version }}/src/liblua.a \ + ${{ matrix.lua_lib }} \ -lm -ldl - name: Test run @@ -135,23 +174,27 @@ jobs: dist/moon -e 'print "hello world"' dist/moonc -h + - name: Test JIT + if: matrix.runtime == 'luajit' + run: dist/moon -e 'print jit.version' + - name: Upload artifact uses: actions/upload-artifact@v6 with: - name: moonscript-${{ env.VERSION_SUFFIX }}-linux-lua${{ matrix.lua_version }}${{ matrix.artifact_suffix }} + name: moonscript-${{ env.VERSION_SUFFIX }}-linux-${{ matrix.runtime_label }}${{ matrix.artifact_suffix }} path: dist/ - name: Package for release if: github.ref_type == 'tag' run: | cd dist - tar -czvf ../moonscript-${{ env.VERSION_SUFFIX }}-linux-${{ matrix.architecture }}.tar.gz * + tar -czvf ../moonscript-${{ env.VERSION_SUFFIX }}-linux-${{ matrix.architecture }}${{ matrix.release_suffix }}.tar.gz * - name: Upload to release if: github.ref_type == 'tag' uses: softprops/action-gh-release@v2 with: - files: moonscript-${{ env.VERSION_SUFFIX }}-linux-${{ matrix.architecture }}.tar.gz + files: moonscript-${{ env.VERSION_SUFFIX }}-linux-${{ matrix.architecture }}${{ matrix.release_suffix }}.tar.gz windows: runs-on: windows-latest @@ -159,7 +202,20 @@ jobs: strategy: matrix: - lua_version: ["5.1.5"] + include: + - runtime: puc + lua_version: "5.1.5" + runtime_label: "lua5.1.5" + release_suffix: "" + msys_install: gcc make curl zip + lua_include: lua-5.1.5/src + lua_lib: lua-5.1.5/src/liblua.a + - runtime: luajit + runtime_label: "luajit2.1" + release_suffix: "-luajit" + msys_install: make curl zip mingw-w64-x86_64-gcc + lua_include: luajit/src + lua_lib: luajit/src/libluajit.a defaults: run: @@ -176,7 +232,7 @@ jobs: - uses: msys2/setup-msys2@v2 with: - install: gcc make curl zip + install: ${{ matrix.msys_install }} - name: Set version suffix shell: bash @@ -191,11 +247,20 @@ jobs: run: gcc -v - name: Setup Lua + if: matrix.runtime == 'puc' run: | curl -L -O https://www.lua.org/ftp/lua-${{ matrix.lua_version }}.tar.gz tar -xzf lua-${{ matrix.lua_version }}.tar.gz cd lua-${{ matrix.lua_version }}/src && make liblua.a + - name: Setup LuaJIT + if: matrix.runtime == 'luajit' + run: | + curl -L -o luajit.tar.gz https://github.com/LuaJIT/LuaJIT/archive/$LUAJIT_COMMIT.tar.gz + tar -xzf luajit.tar.gz + mv LuaJIT-* luajit + make -C luajit/src -j$(nproc) amalg BUILDMODE=static + - name: Get LPeg run: | curl -L -o lpeg.tar.gz https://www.inf.puc-rio.br/~roberto/lpeg/lpeg-1.0.2.tar.gz @@ -210,7 +275,7 @@ jobs: run: | mkdir -p dist gcc -static -o dist/moon.exe \ - -Ilua-${{ matrix.lua_version }}/src/ \ + -I${{ matrix.lua_include }} \ -Ilpeg-1.0.2/ \ -Ibin/binaries/ \ bin/binaries/moon.c \ @@ -220,10 +285,10 @@ jobs: lpeg-1.0.2/lptree.c \ lpeg-1.0.2/lpcode.c \ lpeg-1.0.2/lpprint.c \ - lua-${{ matrix.lua_version }}/src/liblua.a \ + ${{ matrix.lua_lib }} \ -lm gcc -static -o dist/moonc.exe \ - -Ilua-${{ matrix.lua_version }}/src/ \ + -I${{ matrix.lua_include }} \ -Ilpeg-1.0.2/ \ -Ibin/binaries/ \ bin/binaries/moonc.c \ @@ -234,7 +299,7 @@ jobs: lpeg-1.0.2/lpcode.c \ lpeg-1.0.2/lpprint.c \ luafilesystem-1_8_0/src/lfs.c \ - lua-${{ matrix.lua_version }}/src/liblua.a \ + ${{ matrix.lua_lib }} \ -lm - name: Test run @@ -243,20 +308,24 @@ jobs: dist/moon.exe -e 'print "hello world"' dist/moonc.exe -h + - name: Test JIT + if: matrix.runtime == 'luajit' + run: dist/moon.exe -e 'print jit.version' + - name: Upload artifact uses: actions/upload-artifact@v6 with: - name: moonscript-${{ env.VERSION_SUFFIX }}-windows-lua${{ matrix.lua_version }} + name: moonscript-${{ env.VERSION_SUFFIX }}-windows-${{ matrix.runtime_label }} path: dist/ - name: Package for release if: github.ref_type == 'tag' run: | cd dist - zip ../moonscript-${{ env.VERSION_SUFFIX }}-windows-x86_64.zip * + zip ../moonscript-${{ env.VERSION_SUFFIX }}-windows-x86_64${{ matrix.release_suffix }}.zip * - name: Upload to release if: github.ref_type == 'tag' uses: softprops/action-gh-release@v2 with: - files: moonscript-${{ env.VERSION_SUFFIX }}-windows-x86_64.zip + files: moonscript-${{ env.VERSION_SUFFIX }}-windows-x86_64${{ matrix.release_suffix }}.zip From 0416c84c0d4d2c0954665b642ed2a6f202656763 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 24 Jul 2026 09:07:45 -0700 Subject: [PATCH 523/554] add static build info to the binaries --- .github/workflows/binaries.yml | 12 ++++++++++++ bin/binaries/moon.c | 12 ++++++++++++ bin/binaries/moonc.c | 12 ++++++++++++ moonscript/version.lua | 12 +++++++++++- moonscript/version.moon | 9 ++++++++- 5 files changed, 55 insertions(+), 2 deletions(-) diff --git a/.github/workflows/binaries.yml b/.github/workflows/binaries.yml index f18cabd4..8a06cff0 100644 --- a/.github/workflows/binaries.yml +++ b/.github/workflows/binaries.yml @@ -102,6 +102,8 @@ jobs: else echo "VERSION_SUFFIX=$(git rev-parse --short HEAD)" >> $GITHUB_ENV fi + # commit time, not wall clock, so identical inputs build identical binaries + echo "BUILD_TIME=$(git show -s --format=%cI HEAD)" >> $GITHUB_ENV - name: Download headers uses: actions/download-artifact@v4 @@ -144,6 +146,8 @@ jobs: -I${{ matrix.lua_include }} \ -Ilpeg-1.0.2/ \ -Ibin/binaries/ \ + -DMOON_BUILD_COMMIT="\"${{ env.VERSION_SUFFIX }}\"" \ + -DMOON_BUILD_TIME="\"${{ env.BUILD_TIME }}\"" \ bin/binaries/moon.c \ bin/binaries/moonscript.c \ lpeg-1.0.2/lpvm.c \ @@ -157,6 +161,8 @@ jobs: -I${{ matrix.lua_include }} \ -Ilpeg-1.0.2/ \ -Ibin/binaries/ \ + -DMOON_BUILD_COMMIT="\"${{ env.VERSION_SUFFIX }}\"" \ + -DMOON_BUILD_TIME="\"${{ env.BUILD_TIME }}\"" \ bin/binaries/moonc.c \ bin/binaries/moonscript.c \ lpeg-1.0.2/lpvm.c \ @@ -242,6 +248,8 @@ jobs: else echo "VERSION_SUFFIX=$(git rev-parse --short HEAD)" >> $GITHUB_ENV fi + # commit time, not wall clock, so identical inputs build identical binaries + echo "BUILD_TIME=$(git show -s --format=%cI HEAD)" >> $GITHUB_ENV - name: Show GCC run: gcc -v @@ -278,6 +286,8 @@ jobs: -I${{ matrix.lua_include }} \ -Ilpeg-1.0.2/ \ -Ibin/binaries/ \ + -DMOON_BUILD_COMMIT="\"${{ env.VERSION_SUFFIX }}\"" \ + -DMOON_BUILD_TIME="\"${{ env.BUILD_TIME }}\"" \ bin/binaries/moon.c \ bin/binaries/moonscript.c \ lpeg-1.0.2/lpvm.c \ @@ -291,6 +301,8 @@ jobs: -I${{ matrix.lua_include }} \ -Ilpeg-1.0.2/ \ -Ibin/binaries/ \ + -DMOON_BUILD_COMMIT="\"${{ env.VERSION_SUFFIX }}\"" \ + -DMOON_BUILD_TIME="\"${{ env.BUILD_TIME }}\"" \ bin/binaries/moonc.c \ bin/binaries/moonscript.c \ lpeg-1.0.2/lpvm.c \ diff --git a/bin/binaries/moon.c b/bin/binaries/moon.c index f668d436..911b3695 100644 --- a/bin/binaries/moon.c +++ b/bin/binaries/moon.c @@ -16,6 +16,18 @@ int main(int argc, char **argv) { luaopen_moonscript(l); lua_pop(l, 1); +#ifdef MOON_BUILD_COMMIT + // Build metadata passed in by CI; moonscript.version prints it with -v + lua_newtable(l); + lua_pushstring(l, LUA_RELEASE); + lua_setfield(l, -2, "lua"); + lua_pushstring(l, MOON_BUILD_COMMIT); + lua_setfield(l, -2, "commit"); + lua_pushstring(l, MOON_BUILD_TIME); + lua_setfield(l, -2, "time"); + lua_setglobal(l, "MOON_BUILD_INFO"); +#endif + // Set up arg table lua_newtable(l); lua_pushstring(l, "moon"); diff --git a/bin/binaries/moonc.c b/bin/binaries/moonc.c index 9cd9a67b..595360d6 100644 --- a/bin/binaries/moonc.c +++ b/bin/binaries/moonc.c @@ -30,6 +30,18 @@ int main(int argc, char **argv) { } lua_pop(l, nresults); +#ifdef MOON_BUILD_COMMIT + // Build metadata passed in by CI; moonscript.version prints it with -v + lua_newtable(l); + lua_pushstring(l, LUA_RELEASE); + lua_setfield(l, -2, "lua"); + lua_pushstring(l, MOON_BUILD_COMMIT); + lua_setfield(l, -2, "commit"); + lua_pushstring(l, MOON_BUILD_TIME); + lua_setfield(l, -2, "time"); + lua_setglobal(l, "MOON_BUILD_INFO"); +#endif + // Set up arg table lua_newtable(l); lua_pushstring(l, "moonc"); diff --git a/moonscript/version.lua b/moonscript/version.lua index 715b8291..000af08d 100644 --- a/moonscript/version.lua +++ b/moonscript/version.lua @@ -2,6 +2,16 @@ local version = "0.6.0" return { version = version, print_version = function() - return print("MoonScript version " .. tostring(version)) + do + local build = MOON_BUILD_INFO + if build then + print("MoonScript version " .. tostring(version) .. " (static build)") + print("Runtime: " .. tostring(jit and jit.version or build.lua)) + print("Commit: " .. tostring(build.commit)) + return print("Built: " .. tostring(build.time)) + else + return print("MoonScript version " .. tostring(version)) + end + end end } diff --git a/moonscript/version.moon b/moonscript/version.moon index 931665cb..f6533c47 100644 --- a/moonscript/version.moon +++ b/moonscript/version.moon @@ -4,5 +4,12 @@ version = "0.6.0" { version: version, print_version: -> - print "MoonScript version #{version}" + -- MOON_BUILD_INFO is only set by the static binary wrappers (bin/binaries) + if build = MOON_BUILD_INFO + print "MoonScript version #{version} (static build)" + print "Runtime: #{jit and jit.version or build.lua}" + print "Commit: #{build.commit}" + print "Built: #{build.time}" + else + print "MoonScript version #{version}" } From 1939ca72fd800d8cf583c2e6f85be67b464866e0 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 24 Jul 2026 10:08:24 -0700 Subject: [PATCH 524/554] continue and varargs implement in transfromation instead of "listeners" in compiler, remove "listen", "unlisten", "send" and "splice" from Block --- moonscript/compile.lua | 28 +----- moonscript/compile.moon | 19 ---- moonscript/compile/statement.lua | 7 -- moonscript/compile/statement.moon | 4 - moonscript/compile/value.lua | 17 +--- moonscript/compile/value.moon | 12 +-- moonscript/transform/statement.lua | 138 ++++++++++++--------------- moonscript/transform/statement.moon | 69 +++++++------- moonscript/transform/statements.lua | 68 ++++++++++++- moonscript/transform/statements.moon | 46 ++++++++- moonscript/transform/value.lua | 32 ++----- moonscript/transform/value.moon | 23 ++--- spec/inputs/assign.moon | 6 ++ spec/inputs/loops.moon | 24 +++++ spec/outputs/assign.lua | 17 +++- spec/outputs/loops.lua | 69 ++++++++++++++ 16 files changed, 345 insertions(+), 234 deletions(-) diff --git a/moonscript/compile.lua b/moonscript/compile.lua index 2eb4df16..fedb351e 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -277,20 +277,6 @@ do get_current = function(self, name) return rawget(self._state, name) end, - listen = function(self, name, fn) - self._listeners[name] = fn - end, - unlisten = function(self, name) - self._listeners[name] = nil - end, - send = function(self, name, ...) - do - local fn = self._listeners[name] - if fn then - return fn(self, ...) - end - end - end, extract_assign_name = function(self, node) local is_local = false local real_name @@ -565,14 +551,6 @@ do self.current_stms = current_stms self.current_stm_i = current_stm_i return nil - end, - splice = function(self, fn) - local lines = { - "lines", - self._lines - } - self._lines = Lines() - return self:stms(fn(lines)) end } _base_0.__index = _base_0 @@ -582,7 +560,6 @@ do self._lines = Lines() self._names = { } self._state = { } - self._listeners = { } do self.transform = { value = transform.Value:bind(self), @@ -592,12 +569,9 @@ do if self.parent then self.root = self.parent.root self.indent = self.parent.indent + 1 - setmetatable(self._state, { + return setmetatable(self._state, { __index = self.parent._state }) - return setmetatable(self._listeners, { - __index = self.parent._listeners - }) else self.indent = 0 end diff --git a/moonscript/compile.moon b/moonscript/compile.moon index e6cf00a6..6784a06a 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -174,7 +174,6 @@ class Block @_names = {} @_state = {} - @_listeners = {} with transform @transform = { @@ -186,7 +185,6 @@ class Block @root = @parent.root @indent = @parent.indent + 1 setmetatable @_state, { __index: @parent._state } - setmetatable @_listeners, { __index: @parent._listeners } else @indent = 0 @@ -199,16 +197,6 @@ class Block get_current: (name) => rawget @_state, name - listen: (name, fn) => - @_listeners[name] = fn - - unlisten: (name) => - @_listeners[name] = nil - - send: (name, ...) => - if fn = @_listeners[name] - fn self, ... - extract_assign_name: (node) => is_local = false real_name = switch mtype node @@ -403,13 +391,6 @@ class Block nil - -- takes the existing set of lines and replaces them with the result of - -- calling fn on them - splice: (fn) => - lines = {"lines", @_lines} - @_lines = Lines! - @stms fn lines - class RootBlock extends Block new: (@options) => @root = self diff --git a/moonscript/compile/statement.lua b/moonscript/compile/statement.lua index 7f1c9063..3e935e54 100644 --- a/moonscript/compile/statement.lua +++ b/moonscript/compile/statement.lua @@ -11,13 +11,6 @@ return { raw = function(self, node) 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] local undeclared = self:declare(names) diff --git a/moonscript/compile/statement.moon b/moonscript/compile/statement.moon index 25f53fd0..ac67b7eb 100644 --- a/moonscript/compile/statement.moon +++ b/moonscript/compile/statement.moon @@ -7,10 +7,6 @@ import unpack from require "moonscript.util" { raw: (node) => @add node[2] - lines: (node) => - for line in *node[2] - @add line - declare: (node) => names = node[2] undeclared = @declare names diff --git a/moonscript/compile/value.lua b/moonscript/compile/value.lua index ca6e5041..8908f307 100644 --- a/moonscript/compile/value.lua +++ b/moonscript/compile/value.lua @@ -165,6 +165,7 @@ return { end do local _with_0 = self:block() + _with_0.header = "function(" .. concat(arg_names, ", ") .. ")" if #whitelist > 0 then _with_0:whitelist_names(whitelist) end @@ -221,19 +222,6 @@ return { }) end _with_0:stms(block) - if #args > #arg_names then - do - local _accum_0 = { } - local _len_0 = 1 - for _index_0 = 1, #args do - local arg = args[_index_0] - _accum_0[_len_0] = arg[1] - _len_0 = _len_0 + 1 - end - arg_names = _accum_0 - end - end - _with_0.header = "function(" .. concat(arg_names, ", ") .. ")" return _with_0 end end, @@ -353,9 +341,6 @@ return { return tostring(value[2]) end, raw_value = function(self, value) - if value == "..." then - self:send("varargs") - end return tostring(value) end } diff --git a/moonscript/compile/value.moon b/moonscript/compile/value.moon index 1bfa754b..3abd0ed5 100644 --- a/moonscript/compile/value.moon +++ b/moonscript/compile/value.moon @@ -110,6 +110,8 @@ string_chars = { insert arg_names, 1, "self" with @block! + .header = "function("..concat(arg_names, ", ")..")" + if #whitelist > 0 \whitelist_names whitelist @@ -129,13 +131,6 @@ string_chars = { \stms block - -- inject more args if the block manipulated arguments - -- only varargs bubbling does this currently - if #args > #arg_names -- will only work for simple adjustments - arg_names = [arg[1] for arg in *args] - - .header = "function("..concat(arg_names, ", ")..")" - table: (node) => items = unpack node, 2 with @block "{", "}" @@ -216,8 +211,5 @@ string_chars = { -- catch all pure string values raw_value: (value) => - if value == "..." - @send "varargs" - tostring value } diff --git a/moonscript/transform/statement.lua b/moonscript/transform/statement.lua index e46ce23f..c9cd9aaa 100644 --- a/moonscript/transform/statement.lua +++ b/moonscript/transform/statement.lua @@ -5,10 +5,10 @@ do local _obj_0 = require("moonscript.transform.names") NameProxy, LocalName, is_name_proxy = _obj_0.NameProxy, _obj_0.LocalName, _obj_0.is_name_proxy end -local Run, transform_last_stm, implicitly_return, last_stm +local Run, transform_last_stm, implicitly_return, last_stm, find_continues do local _obj_0 = require("moonscript.transform.statements") - Run, transform_last_stm, implicitly_return, last_stm = _obj_0.Run, _obj_0.transform_last_stm, _obj_0.implicitly_return, _obj_0.last_stm + Run, transform_last_stm, implicitly_return, last_stm, find_continues = _obj_0.Run, _obj_0.transform_last_stm, _obj_0.implicitly_return, _obj_0.last_stm, _obj_0.find_continues end local types = require("moonscript.types") local build, ntype, is_value, smart_node, value_is_singular, is_slice, NOOP @@ -20,77 +20,65 @@ local construct_comprehension construct_comprehension = require("moonscript.transform.comprehension").construct_comprehension local unpack unpack = require("moonscript.util").unpack -local with_continue_listener -with_continue_listener = function(body) - local continue_name = nil +local apply_continue +apply_continue = function(body) + local continues = find_continues(body) + if not (continues[1]) then + return body + end + local continue_name = NameProxy("continue") + for _index_0 = 1, #continues do + local node = continues[_index_0] + node[2] = continue_name + end + local last_type = ntype(last_stm(body)) + local repeat_body + if types.terminating[last_type] or last_type == "continue" then + repeat_body = { + { + "do", + body + } + } + else + repeat_body = body + end + insert(repeat_body, { + "assign", + { + continue_name + }, + { + "true" + } + }) return { - Run(function(self) - return self:listen("continue", function() - if not (continue_name) then - continue_name = NameProxy("continue") - self:put_name(continue_name) - end - return continue_name - end) - end), - build.group(body), - Run(function(self) - if not (continue_name) then - return - end - local last = last_stm(body) - local enclose_lines = types.terminating[last and ntype(last)] - self:put_name(continue_name, nil) - return self:splice(function(lines) - if enclose_lines then - lines = { - "do", - { - lines - } - } - end - return { - { - "assign", - { - continue_name - }, - { - "false" - } - }, - { - "repeat", - "true", - { - lines, - { - "assign", - { - continue_name - }, - { - "true" - } - } - } - }, - { - "if", - { - "not", - continue_name - }, - { - { - "break" - } - } - } + { + "assign", + { + continue_name + }, + { + "false" + } + }, + { + "repeat", + "true", + repeat_body + }, + { + "if", + { + "not", + continue_name + }, + { + { + "break" } - end) - end) + } + } } end local extract_declarations @@ -307,7 +295,7 @@ return Transformer({ return node end, continue = function(self, node) - local continue_name = self:send("continue") + local continue_name = node[2] if not (continue_name) then error("continue must be inside of a loop") end @@ -774,15 +762,15 @@ return Transformer({ }) }) end - node.body = with_continue_listener(node.body) + node.body = apply_continue(node.body) end, ["while"] = function(self, node) smart_node(node) - node.body = with_continue_listener(node.body) + node.body = apply_continue(node.body) end, ["for"] = function(self, node) smart_node(node) - node.body = with_continue_listener(node.body) + node.body = apply_continue(node.body) end, switch = function(self, node, ret) local exp, conds = unpack(node, 2) diff --git a/moonscript/transform/statement.moon b/moonscript/transform/statement.moon index aa834b1a..936962ab 100644 --- a/moonscript/transform/statement.moon +++ b/moonscript/transform/statement.moon @@ -2,7 +2,7 @@ import Transformer from require "moonscript.transform.transformer" import NameProxy, LocalName, is_name_proxy from require "moonscript.transform.names" -import Run, transform_last_stm, implicitly_return, last_stm +import Run, transform_last_stm, implicitly_return, last_stm, find_continues from require "moonscript.transform.statements" types = require "moonscript.types" @@ -17,38 +17,35 @@ import construct_comprehension from require "moonscript.transform.comprehension" import unpack from require "moonscript.util" -with_continue_listener = (body) -> - continue_name = nil +-- binds the continue statements in a loop body to a loop-local flag, +-- wrapping the body in a repeat block that continue can break out of +apply_continue = (body) -> + continues = find_continues body + return body unless continues[1] + + continue_name = NameProxy "continue" + + -- attach the name in place, the continue transformer expands the node when + -- the compiler reaches it so cascading transforms still see a continue + for node in *continues + node[2] = continue_name + + last_type = ntype last_stm body + + -- a trailing continue expands to a break, which must also be enclosed + repeat_body = if types.terminating[last_type] or last_type == "continue" + { {"do", body} } + else + body + + insert repeat_body, {"assign", {continue_name}, {"true"}} { - Run => - @listen "continue", -> - unless continue_name - continue_name = NameProxy"continue" - @put_name continue_name - continue_name - - build.group body - - Run => - return unless continue_name - last = last_stm body - enclose_lines = types.terminating[last and ntype(last)] - - @put_name continue_name, nil - @splice (lines) -> - lines = {"do", {lines}} if enclose_lines - - { - {"assign", {continue_name}, {"false"}} - {"repeat", "true", { - lines - {"assign", {continue_name}, {"true"}} - }} - {"if", {"not", continue_name}, { - {"break"} - }} - } + {"assign", {continue_name}, {"false"}} + {"repeat", "true", repeat_body} + {"if", {"not", continue_name}, { + {"break"} + }} } @@ -197,8 +194,10 @@ Transformer { node + -- apply_continue binds the loop's flag to the node, a continue without one + -- is outside of any loop continue: (node) => - continue_name = @send "continue" + continue_name = node[2] error "continue must be inside of a loop" unless continue_name build.group { build.assign_one continue_name, "true" @@ -460,15 +459,15 @@ Transformer { } } - node.body = with_continue_listener node.body + node.body = apply_continue node.body while: (node) => smart_node node - node.body = with_continue_listener node.body + node.body = apply_continue node.body for: (node) => smart_node node - node.body = with_continue_listener node.body + node.body = apply_continue node.body switch: (node, ret) => exp, conds = unpack node, 2 diff --git a/moonscript/transform/statements.lua b/moonscript/transform/statements.lua index 6a49b77e..22380333 100644 --- a/moonscript/transform/statements.lua +++ b/moonscript/transform/statements.lua @@ -3,6 +3,8 @@ local ntype, mtype, is_value, NOOP ntype, mtype, is_value, NOOP = types.ntype, types.mtype, types.is_value, types.NOOP local comprehension_has_value comprehension_has_value = require("moonscript.transform.comprehension").comprehension_has_value +local insert +insert = table.insert local Run do local _class_0 @@ -74,6 +76,68 @@ chain_is_stub = function(chain) local stub = chain[#chain] return stub and ntype(stub) == "colon" end +local continue_boundaries = { + fndef = true, + ["while"] = true, + ["for"] = true, + foreach = true, + comprehension = true, + tblcomprehension = true +} +local find_continues +find_continues = function(tbl, out) + if out == nil then + out = { } + end + for _index_0 = 1, #tbl do + local item = tbl[_index_0] + if type(item) == "table" then + if item[1] == "continue" then + insert(out, item) + elseif not continue_boundaries[item[1]] then + find_continues(item, out) + end + end + end + return out +end +local has_varargs +has_varargs = function(tbl) + for _index_0 = 1, #tbl do + local _continue_0 = false + repeat + local item = tbl[_index_0] + local _exp_0 = type(item) + if "string" == _exp_0 then + if item == "..." then + return true + end + elseif "table" == _exp_0 then + local _exp_1 = item[1] + if "fndef" == _exp_1 then + _continue_0 = true + break + elseif "string" == _exp_1 then + for i = 3, #item do + local part = item[i] + if type(part) == "table" and has_varargs(part) then + return true + end + end + else + if has_varargs(item) then + return true + end + end + end + _continue_0 = true + until true + if not _continue_0 then + break + end + end + return false +end local implicitly_return implicitly_return = function(scope) local is_top = true @@ -111,5 +175,7 @@ return { last_stm = last_stm, transform_last_stm = transform_last_stm, chain_is_stub = chain_is_stub, - implicitly_return = implicitly_return + implicitly_return = implicitly_return, + find_continues = find_continues, + has_varargs = has_varargs } diff --git a/moonscript/transform/statements.moon b/moonscript/transform/statements.moon index 164e6b58..efd8a2fc 100644 --- a/moonscript/transform/statements.moon +++ b/moonscript/transform/statements.moon @@ -4,6 +4,8 @@ import ntype, mtype, is_value, NOOP from types import comprehension_has_value from require "moonscript.transform.comprehension" +import insert from table + -- A Run is a special statement node that lets a function run and mutate the -- state of the compiler class Run @@ -47,6 +49,47 @@ chain_is_stub = (chain) -> stub = chain[#chain] stub and ntype(stub) == "colon" +-- nodes that a continue statement binds to, a continue found inside one of +-- these belongs to that construct and not the enclosing loop +continue_boundaries = { + fndef: true + while: true + for: true + foreach: true + comprehension: true + tblcomprehension: true +} + +-- collect the continue nodes in a body that bind to the enclosing loop +find_continues = (tbl, out={}) -> + for item in *tbl + if type(item) == "table" + if item[1] == "continue" + insert out, item + elseif not continue_boundaries[item[1]] + find_continues item, out + out + +-- does a body reference the enclosing function's varargs. Nested functions +-- have their own varargs, string nodes hold literal text at string positions +has_varargs = (tbl) -> + for item in *tbl + switch type item + when "string" + return true if item == "..." + when "table" + switch item[1] + when "fndef" + continue + when "string" + for i = 3, #item + part = item[i] + if type(part) == "table" and has_varargs part + return true + else + return true if has_varargs item + false + implicitly_return = (scope) -> is_top = true fn = (stm) -> @@ -74,5 +117,6 @@ implicitly_return = (scope) -> fn -{:Run, :last_stm, :transform_last_stm, :chain_is_stub, :implicitly_return } +{:Run, :last_stm, :transform_last_stm, :chain_is_stub, :implicitly_return, + :find_continues, :has_varargs } diff --git a/moonscript/transform/value.lua b/moonscript/transform/value.lua index 33aaef99..bd7aeb46 100644 --- a/moonscript/transform/value.lua +++ b/moonscript/transform/value.lua @@ -14,10 +14,10 @@ do end local lua_keywords lua_keywords = require("moonscript.data").lua_keywords -local Run, transform_last_stm, implicitly_return, chain_is_stub +local transform_last_stm, implicitly_return, chain_is_stub, has_varargs do local _obj_0 = require("moonscript.transform.statements") - Run, transform_last_stm, implicitly_return, chain_is_stub = _obj_0.Run, _obj_0.transform_last_stm, _obj_0.implicitly_return, _obj_0.chain_is_stub + transform_last_stm, implicitly_return, chain_is_stub, has_varargs = _obj_0.transform_last_stm, _obj_0.implicitly_return, _obj_0.chain_is_stub, _obj_0.has_varargs end local construct_comprehension construct_comprehension = require("moonscript.transform.comprehension").construct_comprehension @@ -135,12 +135,6 @@ return Transformer({ fndef = function(self, node) smart_node(node) node.body = transform_last_stm(node.body, implicitly_return(self)) - node.body = { - Run(function(self) - return self:listen("varargs", function() end) - end), - unpack(node.body) - } return node end, ["if"] = function(self, node) @@ -235,22 +229,16 @@ return Transformer({ end, block_exp = function(self, node) local body = unpack(node, 2) - local fn = nil local arg_list = { } - fn = smart_node(build.fndef({ - body = { - Run(function(self) - return self:listen("varargs", function() - insert(arg_list, "...") - insert(fn.args, { - "..." - }) - return self:unlisten("varargs") - end) - end), - unpack(body) - } + local fn = smart_node(build.fndef({ + body = body })) + if has_varargs(body) then + insert(arg_list, "...") + insert(fn.args, { + "..." + }) + end return build.chain({ base = { "parens", diff --git a/moonscript/transform/value.moon b/moonscript/transform/value.moon index 04e16ae2..2779709a 100644 --- a/moonscript/transform/value.moon +++ b/moonscript/transform/value.moon @@ -5,7 +5,7 @@ import NameProxy from require "moonscript.transform.names" import Accumulator, default_accumulator from require "moonscript.transform.accumulator" import lua_keywords from require "moonscript.data" -import Run, transform_last_stm, implicitly_return, chain_is_stub from require "moonscript.transform.statements" +import transform_last_stm, implicitly_return, chain_is_stub, has_varargs from require "moonscript.transform.statements" import construct_comprehension from require "moonscript.transform.comprehension" @@ -83,11 +83,6 @@ Transformer { fndef: (node) => smart_node node node.body = transform_last_stm node.body, implicitly_return self - node.body = { - Run => @listen "varargs", -> -- capture event - unpack node.body - } - node if: (node) => @@ -146,18 +141,14 @@ Transformer { block_exp: (node) => body = unpack node, 2 - fn = nil arg_list = {} + fn = smart_node build.fndef body: body - fn = smart_node build.fndef body: { - Run => - @listen "varargs", -> - insert arg_list, "..." - insert fn.args, {"..."} - @unlisten "varargs" - - unpack body - } + -- if the body references varargs then the wrapper function must accept + -- and forward them so they remain visible + if has_varargs body + insert arg_list, "..." + insert fn.args, {"..."} build.chain { base: {"parens", fn}, {"call", arg_list} } } diff --git a/spec/inputs/assign.moon b/spec/inputs/assign.moon index 1e5e7a6f..59a6f7f8 100644 --- a/spec/inputs/assign.moon +++ b/spec/inputs/assign.moon @@ -28,3 +28,9 @@ else + +-- multiple names with single complex value + +a, b = x\fn + +a, b, c = x\fn, 1 diff --git a/spec/inputs/loops.moon b/spec/inputs/loops.moon index a704e562..d099edb6 100644 --- a/spec/inputs/loops.moon +++ b/spec/inputs/loops.moon @@ -131,3 +131,27 @@ do print thing + +-- continue as last statement + +while true + print "hello" + continue + +-- continue at end of switch case in accumulating loop + +values = for x in *items + switch x + when "skip" + continue + else + x + +-- nested continues where outer continue comes after inner loop + +for a in *x + for b in *y + continue if b + print b + continue if a + print a diff --git a/spec/outputs/assign.lua b/spec/outputs/assign.lua index cddfda05..1bcc3cad 100644 --- a/spec/outputs/assign.lua +++ b/spec/outputs/assign.lua @@ -27,4 +27,19 @@ if hello then else print("the other") a, b = "nothing", "yeah" -end \ No newline at end of file +end +a, b = (function() + local _base_0 = x + local _fn_0 = _base_0.fn + return function(...) + return _fn_0(_base_0, ...) + end +end)() +local c +a, b, c = (function() + local _base_0 = x + local _fn_0 = _base_0.fn + return function(...) + return _fn_0(_base_0, ...) + end +end)(), 1 \ No newline at end of file diff --git a/spec/outputs/loops.lua b/spec/outputs/loops.lua index 57fe40be..89af865f 100644 --- a/spec/outputs/loops.lua +++ b/spec/outputs/loops.lua @@ -303,4 +303,73 @@ do local thing = xxx[_index_0] print(thing) end +end +while true do + local _continue_0 = false + repeat + do + print("hello") + _continue_0 = true + break + end + _continue_0 = true + until true + if not _continue_0 then + break + end +end +local values +do + local _accum_0 = { } + local _len_0 = 1 + local _list_2 = items + for _index_0 = 1, #_list_2 do + local _continue_0 = false + repeat + local x = _list_2[_index_0] + local _exp_0 = x + if "skip" == _exp_0 then + _continue_0 = true + break + else + _accum_0[_len_0] = x + end + _len_0 = _len_0 + 1 + _continue_0 = true + until true + if not _continue_0 then + break + end + end + values = _accum_0 +end +for _index_0 = 1, #x do + local _continue_0 = false + repeat + local a = x[_index_0] + for _index_1 = 1, #y do + local _continue_1 = false + repeat + local b = y[_index_1] + if b then + _continue_1 = true + break + end + print(b) + _continue_1 = true + until true + if not _continue_1 then + break + end + end + if a then + _continue_0 = true + break + end + print(a) + _continue_0 = true + until true + if not _continue_0 then + break + end end \ No newline at end of file From 922ed724a9f61f75824fa1c47a0f67df801c9dba Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 24 Jul 2026 10:22:42 -0700 Subject: [PATCH 525/554] fix crash when reporting error --- moonscript/compile.lua | 6 +++++- moonscript/compile.moon | 4 ++-- spec/lang_spec.moon | 7 +++++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/moonscript/compile.lua b/moonscript/compile.lua index fedb351e..44d379f0 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -647,6 +647,7 @@ do end local format_error format_error = function(msg, pos, file_str) + msg = tostring(msg) local line_message if pos then local line = pos_to_line(file_str, pos) @@ -688,7 +689,10 @@ tree = function(tree, options) if "user-error" == _exp_0 or "compile-error" == _exp_0 then error_msg, error_pos = unpack(err, 2) else - error_msg, error_pos = error("Unknown error thrown", util.dump(error_msg)) + error_msg, error_pos = concat({ + "Unknown error thrown: " .. tostring(util.dump(err)), + debug.traceback(runner) + }, "\n") end else error_msg, error_pos = concat({ diff --git a/moonscript/compile.moon b/moonscript/compile.moon index 6784a06a..3b0ebbb7 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -410,6 +410,7 @@ class RootBlock extends Block table.concat buffer format_error = (msg, pos, file_str) -> + msg = tostring msg line_message = if pos line = pos_to_line file_str, pos line_str, line = get_closest_line file_str, line @@ -444,8 +445,7 @@ tree = (tree, options={}) -> when "user-error", "compile-error" unpack err, 2 else - -- unknown error, bubble it - error "Unknown error thrown", util.dump error_msg + concat {"Unknown error thrown: #{util.dump err}", debug.traceback runner}, "\n" else concat {err, debug.traceback runner}, "\n" diff --git a/spec/lang_spec.moon b/spec/lang_spec.moon index b0fa1bab..c39a8d8b 100644 --- a/spec/lang_spec.moon +++ b/spec/lang_spec.moon @@ -32,11 +32,14 @@ pcall -> gettime or= os.clock +-- nil-safe capture of all return values +pack = (...) -> {n: select("#", ...), ...} + benchmark = (fn) -> if gettime start = gettime! - res = {fn!} - gettime! - start, unpack res + res = pack fn! + gettime! - start, unpack res, 1, res.n else nil, fn! From c6a6030b56d756343ab9a3826bffdcb178885ab8 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 24 Jul 2026 10:34:40 -0700 Subject: [PATCH 526/554] support destructures within multiple return values, fixes #367 #304 --- moonscript/transform/destructure.lua | 86 +++++++++++++++++++++-- moonscript/transform/destructure.moon | 53 ++++++++++++-- spec/inputs/destructure_multi_return.moon | 12 ++++ spec/outputs/destructure_multi_return.lua | 24 +++++++ spec/transform_spec.moon | 43 ++++++++++++ 5 files changed, 204 insertions(+), 14 deletions(-) create mode 100644 spec/inputs/destructure_multi_return.moon create mode 100644 spec/outputs/destructure_multi_return.lua diff --git a/moonscript/transform/destructure.lua b/moonscript/transform/destructure.lua index 1e370b7d..2da9ed9f 100644 --- a/moonscript/transform/destructure.lua +++ b/moonscript/transform/destructure.lua @@ -40,6 +40,16 @@ has_destructure = function(names) end return false end +local is_multi_return +is_multi_return = function(node) + if node == "..." then + return true + end + if not (type(node) == "table") then + return false + end + return node[1] == "chain" and ntype(node[#node]) == "call" +end local extract_assign_names extract_assign_names = function(name, accum, prefix) if accum == nil then @@ -154,18 +164,28 @@ split_assign = function(scope, assign) local g = { } local total_names = #names local total_values = #values + local suffix_start + if total_names > total_values and is_multi_return(values[total_values]) then + for i = total_values, total_names do + if ntype(names[i]) == "table" then + suffix_start = total_values + break + end + end + end local start = 1 - for i, n in ipairs(names) do + local stop = suffix_start and suffix_start - 1 or total_names + for i = 1, stop do + local n = names[i] if ntype(n) == "table" then if i > start then - local stop = i - 1 insert(g, { "assign", (function() local _accum_0 = { } local _len_0 = 1 - for i = start, stop do - _accum_0[_len_0] = names[i] + for j = start, i - 1 do + _accum_0[_len_0] = names[j] _len_0 = _len_0 + 1 end return _accum_0 @@ -173,8 +193,8 @@ split_assign = function(scope, assign) (function() local _accum_0 = { } local _len_0 = 1 - for i = start, stop do - _accum_0[_len_0] = values[i] + for j = start, i - 1 do + _accum_0[_len_0] = values[j] _len_0 = _len_0 + 1 end return _accum_0 @@ -185,7 +205,59 @@ split_assign = function(scope, assign) start = i + 1 end end - if total_names >= start or total_values >= start then + if suffix_start then + if start <= stop then + insert(g, { + "assign", + (function() + local _accum_0 = { } + local _len_0 = 1 + for j = start, stop do + _accum_0[_len_0] = names[j] + _len_0 = _len_0 + 1 + end + return _accum_0 + end)(), + (function() + local _accum_0 = { } + local _len_0 = 1 + for j = start, stop do + _accum_0[_len_0] = values[j] + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + }) + end + local suffix_names = { } + local destructures = { } + for i = suffix_start, total_names do + local name = names[i] + if ntype(name) == "table" then + local proxy = NameProxy("destruct") + insert(suffix_names, proxy) + insert(destructures, { + name, + proxy + }) + else + insert(suffix_names, name) + end + end + insert(g, { + "assign", + suffix_names, + { + values[total_values] + } + }) + for _index_0 = 1, #destructures do + local _des_0 = destructures[_index_0] + local literal, proxy + literal, proxy = _des_0[1], _des_0[2] + insert(g, build_assign(scope, literal, proxy)) + end + elseif total_names >= start or total_values >= start then local name_slice if total_names < start then name_slice = { diff --git a/moonscript/transform/destructure.moon b/moonscript/transform/destructure.moon index b0413b2d..28e37330 100644 --- a/moonscript/transform/destructure.moon +++ b/moonscript/transform/destructure.moon @@ -19,6 +19,12 @@ has_destructure = (names) -> return true if ntype(n) == "table" false +-- can this value provide more than one return value +is_multi_return = (node) -> + return true if node == "..." + return false unless type(node) == "table" + node[1] == "chain" and ntype(node[#node]) == "call" + extract_assign_names = (name, accum={}, prefix={}) -> i = 1 @@ -93,26 +99,59 @@ split_assign = (scope, assign) -> total_names = #names total_values = #values + -- if the final value can return multiple values then the names consuming + -- its returns must be assigned in a single statement. destructuring + -- literals among them receive a temporary that is unpacked afterwards + local suffix_start + if total_names > total_values and is_multi_return values[total_values] + for i=total_values, total_names + if ntype(names[i]) == "table" + suffix_start = total_values + break + -- We have to break apart the assign into groups of regular -- assigns, and then the destructuring assignments start = 1 - for i, n in ipairs names + stop = suffix_start and suffix_start - 1 or total_names + for i=1, stop + n = names[i] if ntype(n) == "table" if i > start - stop = i - 1 insert g, { "assign" - for i=start,stop - names[i] - for i=start,stop - values[i] + for j=start,i-1 do names[j] + for j=start,i-1 do values[j] } insert g, build_assign scope, n, values[i] start = i + 1 - if total_names >= start or total_values >= start + if suffix_start + -- plain names left over between the last destructure and the suffix + if start <= stop + insert g, { + "assign" + for j=start,stop do names[j] + for j=start,stop do values[j] + } + + suffix_names = {} + destructures = {} + for i=suffix_start, total_names + name = names[i] + if ntype(name) == "table" + proxy = NameProxy "destruct" + insert suffix_names, proxy + insert destructures, {name, proxy} + else + insert suffix_names, name + + insert g, {"assign", suffix_names, {values[total_values]}} + + for {literal, proxy} in *destructures + insert g, build_assign scope, literal, proxy + elseif total_names >= start or total_values >= start name_slice = if total_names < start {"_"} else diff --git a/spec/inputs/destructure_multi_return.moon b/spec/inputs/destructure_multi_return.moon new file mode 100644 index 00000000..509fcff1 --- /dev/null +++ b/spec/inputs/destructure_multi_return.moon @@ -0,0 +1,12 @@ + +num, {:message} = two_values! + +{:alpha}, {:beta}, {:gamma} = multi_destruct! + +head, {:content}, tail = mix! + +start, {:extra}, rest = forward 88, 77 + +prop, {:value} = hello.world! + +{value: built}, {:status} = builder\build! diff --git a/spec/outputs/destructure_multi_return.lua b/spec/outputs/destructure_multi_return.lua new file mode 100644 index 00000000..8ae05835 --- /dev/null +++ b/spec/outputs/destructure_multi_return.lua @@ -0,0 +1,24 @@ +local num, _destruct_0 = two_values() +local message +message = _destruct_0.message +local _destruct_1, _destruct_2, _destruct_3 = multi_destruct() +local alpha +alpha = _destruct_1.alpha +local beta +beta = _destruct_2.beta +local gamma +gamma = _destruct_3.gamma +local head, _destruct_4, tail = mix() +local content +content = _destruct_4.content +local start, _destruct_5, rest = forward(88, 77) +local extra +extra = _destruct_5.extra +local prop, _destruct_6 = hello.world() +local value +value = _destruct_6.value +local _destruct_7, _destruct_8 = builder:build() +local built +built = _destruct_7.value +local status +status = _destruct_8.status \ No newline at end of file diff --git a/spec/transform_spec.moon b/spec/transform_spec.moon index 9bb06a92..c62cd7a2 100644 --- a/spec/transform_spec.moon +++ b/spec/transform_spec.moon @@ -123,6 +123,49 @@ describe "moonscript.transform.destructure", -> {"assign", { {"ref", "a"} }, { {"ref", "two"} }} }}, out + -- a, {:hello} = func! -- where func returns multiple values, second destructured + it "multiple return value", -> + node = { + "assign" + { + {"ref", "a"} + { "table", { + {{"key_literal", "hello"}, {"ref", "hello"}} + } + } + } + { + {"chain", {"ref", "func"}, {"call", {}}} + } + } + + out = split_assign Block!, node + + assert.same "group", out[1] + assert.same 2, #out[2] + + assign = out[2][1] + assert.same "assign", assign[1] + assert.same {"ref", "a"}, assign[2][1] + tmp = assign[2][2] + assert.same "temp_name", tmp[1] + assert.same { {"chain", {"ref", "func"}, {"call", {}}} }, assign[3] + + destruct_group = out[2][2] + assert.same "group", destruct_group[1] + declare = destruct_group[2][1] + assert.same { "declare", { {"ref", "hello"} } }, declare + + destruct_assign = destruct_group[2][2] + assert.same "assign", destruct_assign[1] + assert.same { {"ref", "hello"} }, destruct_assign[2] + + destruct_value = destruct_assign[3][1] + assert.same "chain", destruct_value[1] + assert.is_true tmp == destruct_value[2] + assert.same "dot", destruct_value[3][1] + assert.same "hello", destruct_value[3][2] + it "extracts names from table destructure", -> des = { From 2b0937fb5710feeb31556dae6844e5cf6b5987be Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 24 Jul 2026 11:36:46 -0700 Subject: [PATCH 527/554] fix destructuring against expression blocks and non-chainable receivers closes #449, closes #411, closes #391, closes #451 --- moonscript/compile/value.lua | 3 +- moonscript/compile/value.moon | 6 +- moonscript/transform/destructure.lua | 34 +++++- moonscript/transform/destructure.moon | 32 +++++- moonscript/transform/statement.lua | 29 +++++- moonscript/transform/statement.moon | 23 +++- spec/inputs/destructure.moon | 39 +++++++ spec/outputs/destructure.lua | 144 +++++++++++++++++++++++++- 8 files changed, 294 insertions(+), 16 deletions(-) diff --git a/moonscript/compile/value.lua b/moonscript/compile/value.lua index 8908f307..6b0c65dc 100644 --- a/moonscript/compile/value.lua +++ b/moonscript/compile/value.lua @@ -118,7 +118,8 @@ return { callee[1] = callee_type .. "_colon" end local callee_value = self:value(callee) - if ntype(callee) == "exp" then + local _exp_0 = ntype(callee) + if "exp" == _exp_0 or "table" == _exp_0 then callee_value = self:line("(", callee_value, ")") end local actions diff --git a/moonscript/compile/value.moon b/moonscript/compile/value.moon index 3abd0ed5..82ba88a8 100644 --- a/moonscript/compile/value.moon +++ b/moonscript/compile/value.moon @@ -83,7 +83,11 @@ string_chars = { callee[1] = callee_type.."_colon" callee_value = @value callee - callee_value = @line "(", callee_value, ")" if ntype(callee) == "exp" + + -- expressions and table literals can't be subscripted directly in lua + switch ntype callee + when "exp", "table" + callee_value = @line "(", callee_value, ")" actions = with @line! \append chain_item action for action in *node[item_offset,] diff --git a/moonscript/transform/destructure.lua b/moonscript/transform/destructure.lua index 2da9ed9f..39d5f16a 100644 --- a/moonscript/transform/destructure.lua +++ b/moonscript/transform/destructure.lua @@ -48,7 +48,14 @@ is_multi_return = function(node) if not (type(node) == "table") then return false end - return node[1] == "chain" and ntype(node[#node]) == "call" + local _exp_0 = node[1] + if "chain" == _exp_0 then + return ntype(node[#node]) == "call" + elseif "explist" == _exp_0 then + return true + else + return false + end end local extract_assign_names extract_assign_names = function(name, accum, prefix) @@ -111,6 +118,29 @@ extract_assign_names = function(name, accum, prefix) end return accum end +local keyword_refs = { + ["nil"] = true, + ["true"] = true, + ["false"] = true +} +local chainable_receiver +chainable_receiver = function(node) + local _exp_0 = type(node) + if "string" == _exp_0 then + return node ~= "..." and not keyword_refs[node] + elseif "table" == _exp_0 then + local _exp_1 = node[1] + if "ref" == _exp_1 then + return not keyword_refs[node[2]] + elseif "chain" == _exp_1 or "self" == _exp_1 or "self_class" == _exp_1 or "temp_name" == _exp_1 or "parens" == _exp_1 or "exp" == _exp_1 or "table" == _exp_1 or "string" == _exp_1 then + return true + else + return false + end + else + return false + end +end local build_assign build_assign = function(scope, destruct_literal, receiver) assert(receiver, "attempting to build destructure assign with no receiver") @@ -123,7 +153,7 @@ build_assign = function(scope, destruct_literal, receiver) values } local obj - if scope:is_local(receiver) or #extracted_names == 1 then + if chainable_receiver(receiver) and (scope:is_local(receiver) or #extracted_names == 1) then obj = receiver else do diff --git a/moonscript/transform/destructure.moon b/moonscript/transform/destructure.moon index 28e37330..4b7861e1 100644 --- a/moonscript/transform/destructure.moon +++ b/moonscript/transform/destructure.moon @@ -23,7 +23,13 @@ has_destructure = (names) -> is_multi_return = (node) -> return true if node == "..." return false unless type(node) == "table" - node[1] == "chain" and ntype(node[#node]) == "call" + switch node[1] + when "chain" + ntype(node[#node]) == "call" + when "explist" + true + else + false extract_assign_names = (name, accum={}, prefix={}) -> @@ -59,6 +65,28 @@ extract_assign_names = (name, accum={}, prefix={}) -> accum +-- can the receiver be referenced directly as the base of a chain? anything +-- not recognized here is copied to a temporary name before destructuring. +-- exp, table and string are chainable because the compiler wraps them in +-- parentheses +keyword_refs = {nil: true, true: true, false: true} + +chainable_receiver = (node) -> + switch type node + when "string" + -- legacy transformers use plain strings for names + node != "..." and not keyword_refs[node] + when "table" + switch node[1] + when "ref" + not keyword_refs[node[2]] + when "chain", "self", "self_class", "temp_name", "parens", "exp", "table", "string" + true + else + false + else + false + build_assign = (scope, destruct_literal, receiver) -> assert receiver, "attempting to build destructure assign with no receiver" @@ -69,7 +97,7 @@ build_assign = (scope, destruct_literal, receiver) -> inner = {"assign", names, values} - obj = if scope\is_local(receiver) or #extracted_names == 1 + obj = if chainable_receiver(receiver) and (scope\is_local(receiver) or #extracted_names == 1) receiver else with obj = NameProxy "obj" diff --git a/moonscript/transform/statement.lua b/moonscript/transform/statement.lua index c9cd9aaa..8c926bac 100644 --- a/moonscript/transform/statement.lua +++ b/moonscript/transform/statement.lua @@ -124,6 +124,23 @@ extract_declarations = function(self, body, start, out) end return out end +local extract_declare_names +extract_declare_names = function(names) + local out = { } + for _index_0 = 1, #names do + local name = names[_index_0] + if ntype(name) == "table" then + local _list_0 = destructure.extract_assign_names(name) + for _index_1 = 1, #_list_0 do + local tuple = _list_0[_index_1] + insert(out, tuple[1]) + end + else + insert(out, name) + end + end + return out +end local expand_elseif_assign expand_elseif_assign = function(ifstm) for i = 4, #ifstm do @@ -240,9 +257,9 @@ return Transformer({ return build.group({ { "declare", - { + extract_declare_names({ first_name - } + }) }, { "do", @@ -282,13 +299,15 @@ return Transformer({ transformed = build.group({ { "declare", - names + extract_declare_names(names) }, self.transform.statement(value, ret, node) }) end end - node = transformed or node + if transformed then + return transformed + end if destructure.has_destructure(names) then return destructure.split_assign(self, node) end @@ -522,7 +541,7 @@ return Transformer({ names = (function() local _accum_0 = { } local _len_0 = 1 - local _list_0 = stm[2] + local _list_0 = extract_declare_names(stm[2]) for _index_0 = 1, #_list_0 do local name = _list_0[_index_0] if ntype(name) == "ref" then diff --git a/moonscript/transform/statement.moon b/moonscript/transform/statement.moon index 936962ab..bf530c59 100644 --- a/moonscript/transform/statement.moon +++ b/moonscript/transform/statement.moon @@ -68,6 +68,19 @@ extract_declarations = (body=@current_stms, start=@current_stm_i + 1, out={}) => extract_declarations @, stm[2], 1, out out +-- the names a declare statement must list for an assignment's names, +-- destructuring literals are replaced by the names they extract so the +-- declaration works when the assignment happens in a deeper scope +extract_declare_names = (names) -> + out = {} + for name in *names + if ntype(name) == "table" + for tuple in *destructure.extract_assign_names name + insert out, tuple[1] + else + insert out, name + out + expand_elseif_assign = (ifstm) -> for i = 4, #ifstm case = ifstm[i] @@ -155,7 +168,7 @@ Transformer { block_body[idx] = build.assign_one first_name, block_body[idx] return build.group { - {"declare", {first_name}} + {"declare", extract_declare_names {first_name}} {"do", block_body} } @@ -183,11 +196,13 @@ Transformer { stm build.group { - {"declare", names} + {"declare", extract_declare_names names} @transform.statement value, ret, node } - node = transformed or node + -- the assigns bubbled into the value's branches handle their own + -- destructuring when they are transformed + return transformed if transformed if destructure.has_destructure names return destructure.split_assign @, node @@ -300,7 +315,7 @@ Transformer { if ntype(stm) == "assign" wrapped = build.group { - build.declare names: [name for name in *stm[2] when ntype(name) == "ref"] + build.declare names: [name for name in *extract_declare_names(stm[2]) when ntype(name) == "ref"] wrapped } diff --git a/spec/inputs/destructure.moon b/spec/inputs/destructure.moon index beb79d67..34acdb76 100644 --- a/spec/inputs/destructure.moon +++ b/spec/inputs/destructure.moon @@ -98,3 +98,42 @@ do (k) -> {a,b,c} = z + +-- destructuring against expression blocks + +{a, b} = for i in *{2, 3} do i * i + +{c, d} = [v * 2 for v in *{1, 2}] + +{:left, :right} = if cond then {left: 1, right: 2} else {left: 3} + +{p, q} = do + {10, 20} + +{:val} = switch x + when 2 then {val: "two"} + +{t} = with something! do .x = 5 + +{u, v} = {7, 8} if cond + +n, {:m} = if cond then 1, {m: 2} + +{:k} = {w, true for w in thing\gmatch "%w"} + +{a: {inner}} = if cond then {a: {"deep"}} + +{lit} = {42} + +{:single} = if cond then {single: 1}, {single: 2} + +-- receivers that can't be chained directly + +grab = (...) -> + {:first_arg} = ... + +{nothing} = nil + +{:negated} = not thing + +{:len} = #thing diff --git a/spec/outputs/destructure.lua b/spec/outputs/destructure.lua index 8254e3c9..eab1dff1 100644 --- a/spec/outputs/destructure.lua +++ b/spec/outputs/destructure.lua @@ -161,8 +161,150 @@ _ = function(z) end do local z = "oo" - return function(k) + _ = function(k) local a, b, c a, b, c = z[1], z[2], z[3] end +end +local a, b +do + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = { + 2, + 3 + } + for _index_0 = 1, #_list_0 do + local i = _list_0[_index_0] + _accum_0[_len_0] = i * i + _len_0 = _len_0 + 1 + end + a, b = _accum_0[1], _accum_0[2] +end +local c, d +do + local _accum_0 = { } + local _len_0 = 1 + local _list_0 = { + 1, + 2 + } + for _index_0 = 1, #_list_0 do + local v = _list_0[_index_0] + _accum_0[_len_0] = v * 2 + _len_0 = _len_0 + 1 + end + c, d = _accum_0[1], _accum_0[2] +end +local left, right +if cond then + do + local _obj_0 = { + left = 1, + right = 2 + } + left, right = _obj_0.left, _obj_0.right + end +else + do + local _obj_0 = { + left = 3 + } + left, right = _obj_0.left, _obj_0.right + end +end +local p, q +do + do + local _obj_0 = { + 10, + 20 + } + p, q = _obj_0[1], _obj_0[2] + end +end +local val +local _exp_0 = x +if 2 == _exp_0 then + val = ({ + val = "two" + }).val +end +local t +do + local _with_0 = something() + _with_0.x = 5 + t = _with_0[1] +end +local u, v +if cond then + do + local _obj_0 = { + 7, + 8 + } + u, v = _obj_0[1], _obj_0[2] + end +end +local n, m +if cond then + local _destruct_0 + n, _destruct_0 = 1, { + m = 2 + } + m = _destruct_0.m +end +local k +do + local _tbl_0 = { } + for w in thing:gmatch("%w") do + _tbl_0[w] = true + end + k = _tbl_0.k +end +local inner +if cond then + inner = ({ + a = { + "deep" + } + }).a[1] +end +local lit +lit = ({ + 42 +})[1] +local single +if cond then + do + local _obj_0 = { + single = 1 + }, { + single = 2 + } + single = _obj_0.single + end +end +local grab +grab = function(...) + local first_arg + do + local _obj_0 = ... + first_arg = _obj_0.first_arg + end +end +local nothing +do + local _obj_0 = nil + nothing = _obj_0[1] +end +local negated +do + local _obj_0 = not thing + negated = _obj_0.negated +end +local len +do + local _obj_0 = #thing + len = _obj_0.len end \ No newline at end of file From 8578b2dc2b23471b0db2e2d60053bf036a289ca1 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 24 Jul 2026 13:39:03 -0700 Subject: [PATCH 528/554] fixes #457 --- moonscript/types.lua | 12 +++++++++++- moonscript/types.moon | 13 ++++++++++++- spec/inputs/syntax.moon | 5 +++++ spec/outputs/syntax.lua | 4 ++++ 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/moonscript/types.lua b/moonscript/types.lua index 0f3a6907..38f4c830 100644 --- a/moonscript/types.lua +++ b/moonscript/types.lua @@ -60,7 +60,17 @@ is_value = function(stm) end local value_is_singular value_is_singular = function(node) - return type(node) ~= "table" or node[1] ~= "exp" or #node == 2 + if type(node) ~= "table" then + return true + end + local _exp_0 = node[1] + if "exp" == _exp_0 then + return #node == 2 and value_is_singular(node[2]) + elseif "length" == _exp_0 or "minus" == _exp_0 or "not" == _exp_0 or "bitnot" == _exp_0 then + return value_is_singular(node[2]) + else + return true + end end local is_slice is_slice = function(node) diff --git a/moonscript/types.moon b/moonscript/types.moon index d7288130..99cd54c7 100644 --- a/moonscript/types.moon +++ b/moonscript/types.moon @@ -52,8 +52,19 @@ is_value = (stm) -> compile.Block\is_value(stm) or transform.Value\can_transform stm +-- is this expression a single term that can sit next to a binary operator +-- without parentheses changing its meaning value_is_singular = (node) -> - type(node) != "table" or node[1] != "exp" or #node == 2 + return true if type(node) != "table" + switch node[1] + when "exp" + #node == 2 and value_is_singular node[2] + when "length", "minus", "not", "bitnot" + -- prefix operators parse greedily but compile without grouping, so a + -- compound operand renders with a trailing operator sequence + value_is_singular node[2] + else + true is_slice = (node) -> ntype(node) == "chain" and ntype(node[#node]) == "slice" diff --git a/spec/inputs/syntax.moon b/spec/inputs/syntax.moon index b5b92a84..31c79d20 100644 --- a/spec/inputs/syntax.moon +++ b/spec/inputs/syntax.moon @@ -165,6 +165,11 @@ a["hello"] += 10 a["hello#{tostring ff}"] += 10 a[four].x += 10 +count -= #datum + 1 +count -= #datum +total *= -x + 1 +flag and= not a or b + x = 0 (if ntype(v) == "fndef" then x += 1) for v in *values diff --git a/spec/outputs/syntax.lua b/spec/outputs/syntax.lua index 8667f348..9a34be5c 100644 --- a/spec/outputs/syntax.lua +++ b/spec/outputs/syntax.lua @@ -170,6 +170,10 @@ local _update_1 = "hello" .. tostring(tostring(ff)) a[_update_1] = a[_update_1] + 10 local _update_2 = four a[_update_2].x = a[_update_2].x + 10 +local count = count - (#datum + 1) +count = count - #datum +local total = total * (-x + 1) +local flag = flag and (not a or b) x = 0 local _list_0 = values for _index_0 = 1, #_list_0 do From 7c216abdd1c1f620bc36a7cad2856328df2ba20b Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 24 Jul 2026 14:08:49 -0700 Subject: [PATCH 529/554] precedence aware parenthases wrapping, fixes #320 --- moonscript/compile/value.lua | 118 +++++++++++++++++++++++++++++++++- moonscript/compile/value.moon | 66 ++++++++++++++++++- spec/inputs/string.moon | 12 ++++ spec/outputs/string.lua | 7 +- 4 files changed, 200 insertions(+), 3 deletions(-) diff --git a/moonscript/compile/value.lua b/moonscript/compile/value.lua index 6b0c65dc..af26d2da 100644 --- a/moonscript/compile/value.lua +++ b/moonscript/compile/value.lua @@ -16,6 +16,78 @@ local string_chars = { ["\r"] = "\\r", ["\n"] = "\\n" } +local binary_op_prec +do + local out = { } + for prec, ops in ipairs({ + { + "or" + }, + { + "and" + }, + { + "<", + ">", + "<=", + ">=", + "~=", + "!=", + "==" + }, + { + "|" + }, + { + "&" + }, + { + "<<", + ">>" + }, + { + ".." + }, + { + "+", + "-" + }, + { + "*", + "/", + "//", + "%" + }, + { + "^" + } + }) do + for _index_0 = 1, #ops do + local op = ops[_index_0] + out[op] = prec + end + end + binary_op_prec = out +end +local right_assoc_op = { + [".."] = true, + ["^"] = true +} +local exp_precedence +exp_precedence = function(node) + local min_prec + for i = 3, #node, 2 do + do + local prec = binary_op_prec[node[i]] + if prec then + if not min_prec or prec < min_prec then + min_prec = prec + end + end + end + end + return min_prec +end return { scoped = function(self, node) local _, before, value, after @@ -28,12 +100,56 @@ return { end end, exp = function(self, node) + local needs_parens + needs_parens = function(value, i) + if not (type(value) == "table" and value[1] == "exp") then + return false + end + local inner = exp_precedence(value) + if not (inner) then + return false + end + if i > 2 then + do + local left = binary_op_prec[node[i - 1]] + if left then + if left > inner then + return true + end + if left == inner and not right_assoc_op[node[i - 1]] then + return true + end + end + end + end + if i < #node then + do + local right = binary_op_prec[node[i + 1]] + if right then + if right > inner then + return true + end + if right == inner and right_assoc_op[node[i + 1]] and node[i + 1] ~= ".." then + return true + end + end + end + end + return false + end local _comp _comp = function(i, value) if i % 2 == 1 and value == "!=" then value = "~=" end - return self:value(value) + if type(value) == "table" then + value = self.transform.value(value) + end + if needs_parens(value, i) then + return self:line("(", self:value(value), ")") + else + return self:value(value) + end end do local _with_0 = self:line() diff --git a/moonscript/compile/value.moon b/moonscript/compile/value.moon index 82ba88a8..db1f7665 100644 --- a/moonscript/compile/value.moon +++ b/moonscript/compile/value.moon @@ -14,6 +14,37 @@ string_chars = { "\n": "\\n" } +-- lua binary operator precedence, from loosest to tightest binding +binary_op_prec = do + out = {} + for prec, ops in ipairs { + {"or"} + {"and"} + {"<", ">", "<=", ">=", "~=", "!=", "=="} + {"|"} + {"&"} + {"<<", ">>"} + {".."} + {"+", "-"} + {"*", "/", "//", "%"} + {"^"} + } + out[op] = prec for op in *ops + out + +right_assoc_op = { + "..": true + "^": true +} + +-- the loosest binding operator in a flat exp node, nil if there are none +exp_precedence = (node) -> + local min_prec + for i=3, #node, 2 + if prec = binary_op_prec[node[i]] + min_prec = prec if not min_prec or prec < min_prec + min_prec + { scoped: (node) => {_, before, value, after} = node @@ -23,10 +54,43 @@ string_chars = { -- list of values separated by binary operators exp: (node) => + -- exp nodes nested by transformations (eg. string interpolation) must + -- keep their grouping if an adjacent operator binds tighter than one of + -- their own operators + needs_parens = (value, i) -> + return false unless type(value) == "table" and value[1] == "exp" + inner = exp_precedence value + return false unless inner + + if i > 2 + if left = binary_op_prec[node[i - 1]] + return true if left > inner + return true if left == inner and not right_assoc_op[node[i - 1]] + + if i < #node + if right = binary_op_prec[node[i + 1]] + return true if right > inner + -- equal precedence on the right regroups under a right associative + -- operator: an exp holding x ^ y rendered flat as x ^ y ^ b + -- evaluates as x ^ (y ^ b). only concat is safe because string + -- concatenation is associative + return true if right == inner and right_assoc_op[node[i + 1]] and node[i + 1] != ".." + + false + _comp = (i, value) -> if i % 2 == 1 and value == "!=" value = "~=" - @value value + + -- transform now so nested exps (eg. from string interpolation) are + -- visible to the parenthesization check + if type(value) == "table" + value = @transform.value value + + if needs_parens value, i + @line "(", @value(value), ")" + else + @value value with @line! \append_list [_comp i,v for i,v in ipairs node when i > 1], " " diff --git a/spec/inputs/string.moon b/spec/inputs/string.moon index 897056a5..db4b1fc0 100644 --- a/spec/inputs/string.moon +++ b/spec/inputs/string.moon @@ -64,3 +64,15 @@ c = 'hello #{hello}' something"hello"\world! something "hello"\world! + +-- interpolation keeps grouping next to tighter binding operators + +x = 10 / "#{b}.5" + +y = 1 + "#{n}0" * 2 + +cmp = a == "v#{b}" + +joined = "a" .. "b#{c}" + +mixed = "#{a}b" * 2 - "c#{d}" diff --git a/spec/outputs/string.lua b/spec/outputs/string.lua index a928c5d3..9b3acd46 100644 --- a/spec/outputs/string.lua +++ b/spec/outputs/string.lua @@ -34,4 +34,9 @@ local _ = "hello"; ("hello"):format().hello(1, 2, 3); ("hello"):format(1, 2, 3) something("hello"):world() -return something(("hello"):world()) \ No newline at end of file +something(("hello"):world()) +x = 10 / (tostring(b) .. ".5") +local y = 1 + (tostring(n) .. "0") * 2 +local cmp = a == "v" .. tostring(b) +local joined = "a" .. "b" .. tostring(c) +local mixed = (tostring(a) .. "b") * 2 - ("c" .. tostring(d)) \ No newline at end of file From e94986d85af17ce34c09c4660ac61bf6d3b68402 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 24 Jul 2026 14:12:30 -0700 Subject: [PATCH 530/554] ensure compiler spec runs with_dev --- spec/compiler_spec.moon | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/spec/compiler_spec.moon b/spec/compiler_spec.moon index 696e6bb9..cae0d08d 100644 --- a/spec/compiler_spec.moon +++ b/spec/compiler_spec.moon @@ -1,25 +1,27 @@ -import Block from require "moonscript.compile" - import ref, str from require "spec.factory" - --- no transform step -class SimpleBlock extends Block - new: (...) => - super ... - @transform = { - value: (...) -> ... - statement: (...) -> ... - } - -value = require "moonscript.compile.value" +import with_dev from require "spec.helpers" describe "moonscript.compile", -> - compile_node = (node) -> - block = SimpleBlock! - block\add block\value node - lines = block._lines\flatten! - lines[#lines] = nil if lines[#lines] == "\n" - table.concat lines + local compile_node + + with_dev -> + import Block from require "moonscript.compile" + + -- no transform step + class SimpleBlock extends Block + new: (...) => + super ... + @transform = { + value: (...) -> ... + statement: (...) -> ... + } + + compile_node = (node) -> + block = SimpleBlock! + block\add block\value node + lines = block._lines\flatten! + lines[#lines] = nil if lines[#lines] == "\n" + table.concat lines -- compiling lua ast describe "value", -> From af0045469ec28f9dac5ecaf8dc63e4e6d9650c7a Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 24 Jul 2026 14:12:47 -0700 Subject: [PATCH 531/554] paren precedence compile specs --- spec/compiler_spec.moon | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/spec/compiler_spec.moon b/spec/compiler_spec.moon index cae0d08d..92ed3a92 100644 --- a/spec/compiler_spec.moon +++ b/spec/compiler_spec.moon @@ -56,6 +56,36 @@ describe "moonscript.compile", -> "a + b ~= c" } + { + "exp (nested under tighter operator)" + -> {"exp", {"exp", ref("a"), "..", ref("b")}, "*", ref("c")} + "(a .. b) * c" + } + + { + "exp (nested under looser operator)" + -> {"exp", ref("a"), "==", {"exp", ref("b"), "..", ref("c")}} + "a == b .. c" + } + + { + "exp (nested right of equal precedence left associative)" + -> {"exp", ref("a"), "-", {"exp", ref("b"), "+", ref("c")}} + "a - (b + c)" + } + + { + "exp (nested concat within concat stays flat)" + -> {"exp", {"exp", ref("a"), "..", ref("b")}, "..", ref("c")} + "a .. b .. c" + } + + { + "exp (nested left of right associative operator)" + -> {"exp", {"exp", ref("x"), "^", ref("y")}, "^", ref("b")} + "(x ^ y) ^ b" + } + { "parens" -> { "parens", ref! } From a2f6c765d6f4844a64cd418256ed5a595afff3ac Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 24 Jul 2026 14:28:16 -0700 Subject: [PATCH 532/554] group #{} interplation with parens over outside operators on strings --- moonscript/compile/value.lua | 2 +- moonscript/compile/value.moon | 7 +++---- spec/compiler_spec.moon | 8 +++++++- spec/inputs/string.moon | 8 ++++++++ spec/outputs/string.lua | 5 ++++- 5 files changed, 23 insertions(+), 7 deletions(-) diff --git a/moonscript/compile/value.lua b/moonscript/compile/value.lua index af26d2da..12c57979 100644 --- a/moonscript/compile/value.lua +++ b/moonscript/compile/value.lua @@ -129,7 +129,7 @@ return { if right > inner then return true end - if right == inner and right_assoc_op[node[i + 1]] and node[i + 1] ~= ".." then + if right == inner and right_assoc_op[node[i + 1]] then return true end end diff --git a/moonscript/compile/value.moon b/moonscript/compile/value.moon index db1f7665..1007d3aa 100644 --- a/moonscript/compile/value.moon +++ b/moonscript/compile/value.moon @@ -71,10 +71,9 @@ exp_precedence = (node) -> if right = binary_op_prec[node[i + 1]] return true if right > inner -- equal precedence on the right regroups under a right associative - -- operator: an exp holding x ^ y rendered flat as x ^ y ^ b - -- evaluates as x ^ (y ^ b). only concat is safe because string - -- concatenation is associative - return true if right == inner and right_assoc_op[node[i + 1]] and node[i + 1] != ".." + -- operator: an exp holding a .. b rendered flat as a .. b .. c + -- evaluates as a .. (b .. c), observable through __concat + return true if right == inner and right_assoc_op[node[i + 1]] false diff --git a/spec/compiler_spec.moon b/spec/compiler_spec.moon index 92ed3a92..3ab9e0d6 100644 --- a/spec/compiler_spec.moon +++ b/spec/compiler_spec.moon @@ -75,8 +75,14 @@ describe "moonscript.compile", -> } { - "exp (nested concat within concat stays flat)" + "exp (nested concat left of concat keeps grouping)" -> {"exp", {"exp", ref("a"), "..", ref("b")}, "..", ref("c")} + "(a .. b) .. c" + } + + { + "exp (nested concat right of concat stays flat)" + -> {"exp", ref("a"), "..", {"exp", ref("b"), "..", ref("c")}} "a .. b .. c" } diff --git a/spec/inputs/string.moon b/spec/inputs/string.moon index db4b1fc0..648eff44 100644 --- a/spec/inputs/string.moon +++ b/spec/inputs/string.moon @@ -76,3 +76,11 @@ cmp = a == "v#{b}" joined = "a" .. "b#{c}" mixed = "#{a}b" * 2 - "c#{d}" + +-- interpolation on the left of concat keeps its grouping for __concat + +prefix = "id: #{id}, " .. rest + +data_url = "data:image/#{kind};base64," .. encode_base64(image_bytes) + +line ..= " #{join} " .. el diff --git a/spec/outputs/string.lua b/spec/outputs/string.lua index 9b3acd46..98e33b8a 100644 --- a/spec/outputs/string.lua +++ b/spec/outputs/string.lua @@ -39,4 +39,7 @@ x = 10 / (tostring(b) .. ".5") local y = 1 + (tostring(n) .. "0") * 2 local cmp = a == "v" .. tostring(b) local joined = "a" .. "b" .. tostring(c) -local mixed = (tostring(a) .. "b") * 2 - ("c" .. tostring(d)) \ No newline at end of file +local mixed = (tostring(a) .. "b") * 2 - ("c" .. tostring(d)) +local prefix = ("id: " .. tostring(id) .. ", ") .. rest +local data_url = ("data:image/" .. tostring(kind) .. ";base64,") .. encode_base64(image_bytes) +local line = line .. ((" " .. tostring(join) .. " ") .. el) \ No newline at end of file From 790e436bfc5e34f3df04f0211c9eef9e98515476 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 24 Jul 2026 15:04:41 -0700 Subject: [PATCH 533/554] clean up user_error usage, be better about passing in a pos --- moonscript/compile.lua | 5 ++- moonscript/compile.moon | 5 +++ moonscript/compile/value.lua | 5 ++- moonscript/compile/value.moon | 6 ++- moonscript/transform/destructure.lua | 2 +- moonscript/transform/destructure.moon | 2 +- moonscript/transform/statement.lua | 4 +- moonscript/transform/statement.moon | 3 +- spec/compile_error_spec.moon | 54 +++++++++++++++++++++++++++ 9 files changed, 77 insertions(+), 9 deletions(-) create mode 100644 spec/compile_error_spec.moon diff --git a/moonscript/compile.lua b/moonscript/compile.lua index 44d379f0..ff1cbc0e 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -266,7 +266,7 @@ do else h = unpack(self.header:render({ })) end - return "Block<" .. tostring(h) .. "> <- " .. tostring(self.parent) + return ("Block<" .. tostring(h) .. "> <- ") .. tostring(self.parent) end, set = function(self, name, value) self._state[name] = value @@ -507,6 +507,9 @@ do if not node then return end + if type(node) == "table" and node[-1] then + self.root.last_pos = node[-1] + end node = self.transform.statement(node) local result do diff --git a/moonscript/compile.moon b/moonscript/compile.moon index 3b0ebbb7..2780de9b 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -359,6 +359,11 @@ class Block stm: (node, ...) => return if not node -- skip blank statements + + -- track the most recent position for errors raised without one + if type(node) == "table" and node[-1] + @root.last_pos = node[-1] + node = @transform.statement node result = if fn = @statement_compilers[ntype(node)] diff --git a/moonscript/compile/value.lua b/moonscript/compile/value.lua index 12c57979..251b4107 100644 --- a/moonscript/compile/value.lua +++ b/moonscript/compile/value.lua @@ -201,7 +201,7 @@ return { if callee_type == "dot" or callee_type == "colon" or callee_type == "index" then callee = self:get("scope_var") if not (callee) then - user_error("Short-dot syntax must be called within a with block") + user_error("Short-dot syntax must be called within a with block", node[-1]) end item_offset = 2 end @@ -213,6 +213,7 @@ return { end end end + local chain_pos = node[-1] local chain_item chain_item = function(node) local t, arg = unpack(node) @@ -225,7 +226,7 @@ return { elseif t == "colon" then return ":", tostring(arg) elseif t == "colon_stub" then - return user_error("Uncalled colon stub") + return user_error("Uncalled colon stub", chain_pos) else return error("Unknown chain action: " .. tostring(t)) end diff --git a/moonscript/compile/value.moon b/moonscript/compile/value.moon index 1007d3aa..79ec986e 100644 --- a/moonscript/compile/value.moon +++ b/moonscript/compile/value.moon @@ -118,7 +118,7 @@ exp_precedence = (node) -> if callee_type == "dot" or callee_type == "colon" or callee_type == "index" callee = @get "scope_var" unless callee - user_error "Short-dot syntax must be called within a with block" + user_error "Short-dot syntax must be called within a with block", node[-1] item_offset = 2 -- TODO: don't use string literals as ref @@ -126,6 +126,8 @@ exp_precedence = (node) -> if sup = @get "super" return @value sup self, node + chain_pos = node[-1] + chain_item = (node) -> t, arg = unpack node if t == "call" @@ -138,7 +140,7 @@ exp_precedence = (node) -> elseif t == "colon" ":", tostring arg elseif t == "colon_stub" - user_error "Uncalled colon stub" + user_error "Uncalled colon stub", chain_pos else error "Unknown chain action: #{t}" diff --git a/moonscript/transform/destructure.lua b/moonscript/transform/destructure.lua index 39d5f16a..01505b92 100644 --- a/moonscript/transform/destructure.lua +++ b/moonscript/transform/destructure.lua @@ -113,7 +113,7 @@ extract_assign_names = function(name, accum, prefix) elseif "table" == _exp_0 then extract_assign_names(value, accum, suffix) else - user_error("Can't destructure value of type: " .. tostring(ntype(value))) + user_error("Can't destructure value of type: " .. tostring(ntype(value)), value[-1] or name[-1]) end end return accum diff --git a/moonscript/transform/destructure.moon b/moonscript/transform/destructure.moon index 4b7861e1..62f5c1b8 100644 --- a/moonscript/transform/destructure.moon +++ b/moonscript/transform/destructure.moon @@ -61,7 +61,7 @@ extract_assign_names = (name, accum={}, prefix={}) -> when "table" extract_assign_names value, accum, suffix else - user_error "Can't destructure value of type: #{ntype value}" + user_error "Can't destructure value of type: #{ntype value}", value[-1] or name[-1] accum diff --git a/moonscript/transform/statement.lua b/moonscript/transform/statement.lua index 8c926bac..51e1c399 100644 --- a/moonscript/transform/statement.lua +++ b/moonscript/transform/statement.lua @@ -20,6 +20,8 @@ local construct_comprehension construct_comprehension = require("moonscript.transform.comprehension").construct_comprehension local unpack unpack = require("moonscript.util").unpack +local user_error +user_error = require("moonscript.errors").user_error local apply_continue apply_continue = function(body) local continues = find_continues(body) @@ -316,7 +318,7 @@ return Transformer({ continue = function(self, node) local continue_name = node[2] if not (continue_name) then - error("continue must be inside of a loop") + user_error("continue must be inside of a loop", node[-1]) end return build.group({ build.assign_one(continue_name, "true"), diff --git a/moonscript/transform/statement.moon b/moonscript/transform/statement.moon index bf530c59..43059a13 100644 --- a/moonscript/transform/statement.moon +++ b/moonscript/transform/statement.moon @@ -16,6 +16,7 @@ destructure = require "moonscript.transform.destructure" import construct_comprehension from require "moonscript.transform.comprehension" import unpack from require "moonscript.util" +import user_error from require "moonscript.errors" -- binds the continue statements in a loop body to a loop-local flag, -- wrapping the body in a repeat block that continue can break out of @@ -213,7 +214,7 @@ Transformer { -- is outside of any loop continue: (node) => continue_name = node[2] - error "continue must be inside of a loop" unless continue_name + user_error "continue must be inside of a loop", node[-1] unless continue_name build.group { build.assign_one continue_name, "true" {"break"} diff --git a/spec/compile_error_spec.moon b/spec/compile_error_spec.moon new file mode 100644 index 00000000..fa5e9667 --- /dev/null +++ b/spec/compile_error_spec.moon @@ -0,0 +1,54 @@ +import with_dev, unindent from require "spec.helpers" + +-- tests the user facing compile errors triggered by invalid code, including +-- the source position they point at +describe "compile errors", -> + local to_error + + with_dev -> + parse = require "moonscript.parse" + compile = require "moonscript.compile" + import pos_to_line from require "moonscript.util" + + to_error = (str) -> + tree = assert parse.string str + code, err, pos = compile.tree tree + assert.is_nil code, "expected compile to fail" + err, pos and pos_to_line str, pos + + for {name, code_str, expected_msg, expected_line} in *{ + { + "short-dot outside of with" + unindent [[ + print "hello" + print "world" + x = .field + ]] + "Short-dot syntax must be called within a with block" + 3 + } + + { + "destructuring invalid value" + unindent [[ + print "hello" + {1} = thing + ]] + "Can't destructure value of type: number" + 2 + } + + { + "continue outside of loop" + unindent [[ + print "hello" + continue + ]] + "continue must be inside of a loop" + 2 + } + } + it name, -> + err, line = to_error code_str + assert.same expected_msg, err + assert.same expected_line, line From aed3d1b3fe2381286a481cc069b60b1f342fc697 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 24 Jul 2026 15:05:38 -0700 Subject: [PATCH 534/554] dont hard error for invalid \stubs that dont have with block, fixes #428 --- moonscript/transform/value.lua | 9 +++++++++ moonscript/transform/value.moon | 8 ++++++++ spec/compile_error_spec.moon | 10 ++++++++++ spec/inputs/with.moon | 6 ++++++ spec/outputs/with.lua | 21 +++++++++++++++++++++ 5 files changed, 54 insertions(+) diff --git a/moonscript/transform/value.lua b/moonscript/transform/value.lua index bd7aeb46..a2ad90bd 100644 --- a/moonscript/transform/value.lua +++ b/moonscript/transform/value.lua @@ -14,6 +14,8 @@ do end local lua_keywords lua_keywords = require("moonscript.data").lua_keywords +local user_error +user_error = require("moonscript.errors").user_error local transform_last_stm, implicitly_return, chain_is_stub, has_varargs do local _obj_0 = require("moonscript.transform.statements") @@ -181,6 +183,13 @@ return Transformer({ local base_name = NameProxy("base") local fn_name = NameProxy("fn") local colon = table.remove(node) + if not (node[2]) then + local scope_var = self:get("scope_var") + if not (scope_var) then + user_error("Short-colon syntax must be called within a with block", node[-1]) + end + node[2] = scope_var + end local is_super = ntype(node[2]) == "ref" and node[2][2] == "super" return build.block_exp({ build.assign({ diff --git a/moonscript/transform/value.moon b/moonscript/transform/value.moon index 2779709a..f84ff67c 100644 --- a/moonscript/transform/value.moon +++ b/moonscript/transform/value.moon @@ -4,6 +4,7 @@ import build, ntype, smart_node from require "moonscript.types" import NameProxy from require "moonscript.transform.names" import Accumulator, default_accumulator from require "moonscript.transform.accumulator" import lua_keywords from require "moonscript.data" +import user_error from require "moonscript.errors" import transform_last_stm, implicitly_return, chain_is_stub, has_varargs from require "moonscript.transform.statements" @@ -114,6 +115,13 @@ Transformer { fn_name = NameProxy "fn" colon = table.remove node + -- a stub with no base takes the scope from the enclosing with block + unless node[2] + scope_var = @get "scope_var" + unless scope_var + user_error "Short-colon syntax must be called within a with block", node[-1] + node[2] = scope_var + is_super = ntype(node[2]) == "ref" and node[2][2] == "super" build.block_exp { build.assign { diff --git a/spec/compile_error_spec.moon b/spec/compile_error_spec.moon index fa5e9667..c009e9aa 100644 --- a/spec/compile_error_spec.moon +++ b/spec/compile_error_spec.moon @@ -17,6 +17,16 @@ describe "compile errors", -> err, pos and pos_to_line str, pos for {name, code_str, expected_msg, expected_line} in *{ + { + "short-colon stub outside of with" + unindent [[ + print "hello" + x = \foo + ]] + "Short-colon syntax must be called within a with block" + 2 + } + { "short-dot outside of with" unindent [[ diff --git a/spec/inputs/with.moon b/spec/inputs/with.moon index ae3c8c05..8e4a5867 100644 --- a/spec/inputs/with.moon +++ b/spec/inputs/with.moon @@ -116,3 +116,9 @@ do with dad .if "yes" y = .end.of.function + + +do + with obj + bound = \method + keyword_bound = \function diff --git a/spec/outputs/with.lua b/spec/outputs/with.lua index 3b2eec3b..7abebde8 100644 --- a/spec/outputs/with.lua +++ b/spec/outputs/with.lua @@ -167,6 +167,27 @@ do local _with_0 = dad _with_0["if"]("yes") local y = _with_0["end"].of["function"] + end +end +do + do + local _with_0 = obj + local bound + do + local _base_0 = _with_0 + local _fn_0 = _base_0.method + bound = function(...) + return _fn_0(_base_0, ...) + end + end + local keyword_bound + do + local _base_0 = _with_0 + local _fn_0 = _base_0["function"] + keyword_bound = function(...) + return _fn_0(_base_0, ...) + end + end return _with_0 end end \ No newline at end of file From 72550baf7a8968aad894d6de24239c0a1409494a Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 24 Jul 2026 15:07:33 -0700 Subject: [PATCH 535/554] remove dead colon_stub reference --- moonscript/compile/value.lua | 3 --- moonscript/compile/value.moon | 4 ---- 2 files changed, 7 deletions(-) diff --git a/moonscript/compile/value.lua b/moonscript/compile/value.lua index 251b4107..f475a940 100644 --- a/moonscript/compile/value.lua +++ b/moonscript/compile/value.lua @@ -213,7 +213,6 @@ return { end end end - local chain_pos = node[-1] local chain_item chain_item = function(node) local t, arg = unpack(node) @@ -225,8 +224,6 @@ return { return ".", tostring(arg) elseif t == "colon" then return ":", tostring(arg) - elseif t == "colon_stub" then - return user_error("Uncalled colon stub", chain_pos) else return error("Unknown chain action: " .. tostring(t)) end diff --git a/moonscript/compile/value.moon b/moonscript/compile/value.moon index 79ec986e..5d2aaf90 100644 --- a/moonscript/compile/value.moon +++ b/moonscript/compile/value.moon @@ -126,8 +126,6 @@ exp_precedence = (node) -> if sup = @get "super" return @value sup self, node - chain_pos = node[-1] - chain_item = (node) -> t, arg = unpack node if t == "call" @@ -139,8 +137,6 @@ exp_precedence = (node) -> ".", tostring arg elseif t == "colon" ":", tostring arg - elseif t == "colon_stub" - user_error "Uncalled colon stub", chain_pos else error "Unknown chain action: #{t}" From 45cec353858c008a049a61b75ffb5582d71c01b3 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 24 Jul 2026 15:08:53 -0700 Subject: [PATCH 536/554] update version number for next release --- moonscript/version.lua | 2 +- moonscript/version.moon | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/moonscript/version.lua b/moonscript/version.lua index 000af08d..db7b74a6 100644 --- a/moonscript/version.lua +++ b/moonscript/version.lua @@ -1,4 +1,4 @@ -local version = "0.6.0" +local version = "0.7.0" return { version = version, print_version = function() diff --git a/moonscript/version.moon b/moonscript/version.moon index f6533c47..3dbf03a3 100644 --- a/moonscript/version.moon +++ b/moonscript/version.moon @@ -1,5 +1,5 @@ -version = "0.6.0" +version = "0.7.0" { version: version, From a5f82a61191f6633f402bc088b43eadbdffab504 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 24 Jul 2026 15:17:50 -0700 Subject: [PATCH 537/554] validate various destructure targets better --- moonscript/parse/util.lua | 28 +++++---------------------- moonscript/parse/util.moon | 16 +-------------- moonscript/transform/destructure.lua | 20 ++++++++++++------- moonscript/transform/destructure.moon | 19 +++++++++++------- moonscript/types.lua | 22 +++++++++++++++++++++ moonscript/types.moon | 19 +++++++++++++++--- moonscript/util.lua | 2 +- spec/compile_error_spec.moon | 10 ++++++++++ spec/inputs/destructure.moon | 4 ++++ spec/outputs/destructure.lua | 3 ++- 10 files changed, 86 insertions(+), 57 deletions(-) diff --git a/moonscript/parse/util.lua b/moonscript/parse/util.lua index 3f02c8d5..fcde7db0 100644 --- a/moonscript/parse/util.lua +++ b/moonscript/parse/util.lua @@ -5,8 +5,11 @@ do local _obj_0 = require("lpeg") P, C, S, Cp, Cmt, V = _obj_0.P, _obj_0.C, _obj_0.S, _obj_0.Cp, _obj_0.Cmt, _obj_0.V end -local ntype -ntype = require("moonscript.types").ntype +local ntype, is_assignable +do + local _obj_0 = require("moonscript.types") + ntype, is_assignable = _obj_0.ntype, _obj_0.is_assignable +end local Space Space = require("moonscript.parse.literals").Space local Indent = C(S("\t ") ^ 0) / function(str) @@ -132,27 +135,6 @@ flatten_or_mark = function(name) return tbl end end -local is_assignable -do - local chain_assignable = { - index = true, - dot = true, - slice = true - } - is_assignable = function(node) - if node == "..." then - return false - end - local _exp_0 = ntype(node) - if "ref" == _exp_0 or "self" == _exp_0 or "value" == _exp_0 or "self_class" == _exp_0 or "table" == _exp_0 then - return true - elseif "chain" == _exp_0 then - return chain_assignable[ntype(node[#node])] - else - return false - end - end -end local check_assignable check_assignable = function(str, pos, value) if is_assignable(value) then diff --git a/moonscript/parse/util.moon b/moonscript/parse/util.moon index 17adf77a..e921645d 100644 --- a/moonscript/parse/util.moon +++ b/moonscript/parse/util.moon @@ -1,7 +1,7 @@ import unpack from require "moonscript.util" import P, C, S, Cp, Cmt, V from require "lpeg" -import ntype from require "moonscript.types" +import ntype, is_assignable from require "moonscript.types" import Space from require "moonscript.parse.literals" -- captures an indentation, returns indent depth @@ -98,20 +98,6 @@ flatten_or_mark = (name) -> table.insert tbl, 1, name tbl --- determines if node is able to be on left side of assignment -is_assignable = do - chain_assignable = { index: true, dot: true, slice: true } - - (node) -> - return false if node == "..." - switch ntype node - when "ref", "self", "value", "self_class", "table" - true - when "chain" - chain_assignable[ntype node[#node]] - else - false - check_assignable = (str, pos, value) -> if is_assignable value true, value diff --git a/moonscript/transform/destructure.lua b/moonscript/transform/destructure.lua index 01505b92..889ddac4 100644 --- a/moonscript/transform/destructure.lua +++ b/moonscript/transform/destructure.lua @@ -1,7 +1,7 @@ -local ntype, mtype, build +local ntype, mtype, build, is_assignable do local _obj_0 = require("moonscript.types") - ntype, mtype, build = _obj_0.ntype, _obj_0.mtype, _obj_0.build + ntype, mtype, build, is_assignable = _obj_0.ntype, _obj_0.mtype, _obj_0.build, _obj_0.is_assignable end local NameProxy NameProxy = require("moonscript.transform.names").NameProxy @@ -104,16 +104,22 @@ extract_assign_names = function(name, accum, prefix) suffix = join(prefix, { suffix }) - local _exp_0 = ntype(value) - if "value" == _exp_0 or "ref" == _exp_0 or "chain" == _exp_0 or "self" == _exp_0 then + if ntype(value) == "table" then + extract_assign_names(value, accum, suffix) + elseif is_assignable(value) then insert(accum, { value, suffix }) - elseif "table" == _exp_0 then - extract_assign_names(value, accum, suffix) else - user_error("Can't destructure value of type: " .. tostring(ntype(value)), value[-1] or name[-1]) + local pos = type(value) == "table" and value[-1] or name[-1] + if value == "..." then + user_error("Can't destructure into '...'", pos) + elseif ntype(value) == "chain" then + user_error("Can't destructure into chain ending in " .. tostring(ntype(value[#value])), pos) + else + user_error("Can't destructure value of type: " .. tostring(ntype(value)), pos) + end end end return accum diff --git a/moonscript/transform/destructure.moon b/moonscript/transform/destructure.moon index 62f5c1b8..287213ce 100644 --- a/moonscript/transform/destructure.moon +++ b/moonscript/transform/destructure.moon @@ -1,5 +1,5 @@ -import ntype, mtype, build from require "moonscript.types" +import ntype, mtype, build, is_assignable from require "moonscript.types" import NameProxy from require "moonscript.transform.names" import insert from table import unpack from require "moonscript.util" @@ -55,13 +55,18 @@ extract_assign_names = (name, accum={}, prefix={}) -> suffix = join prefix, {suffix} - switch ntype value - when "value", "ref", "chain", "self" - insert accum, {value, suffix} - when "table" - extract_assign_names value, accum, suffix + if ntype(value) == "table" + extract_assign_names value, accum, suffix + elseif is_assignable value + insert accum, {value, suffix} + else + pos = type(value) == "table" and value[-1] or name[-1] + if value == "..." + user_error "Can't destructure into '...'", pos + elseif ntype(value) == "chain" + user_error "Can't destructure into chain ending in #{ntype value[#value]}", pos else - user_error "Can't destructure value of type: #{ntype value}", value[-1] or name[-1] + user_error "Can't destructure value of type: #{ntype value}", pos accum diff --git a/moonscript/types.lua b/moonscript/types.lua index 38f4c830..e4edebcd 100644 --- a/moonscript/types.lua +++ b/moonscript/types.lua @@ -58,6 +58,27 @@ is_value = function(stm) local transform = require("moonscript.transform") return compile.Block:is_value(stm) or transform.Value:can_transform(stm) end +local is_assignable +do + local chain_assignable = { + index = true, + dot = true, + slice = true + } + is_assignable = function(node) + if node == "..." then + return false + end + local _exp_0 = ntype(node) + if "ref" == _exp_0 or "self" == _exp_0 or "value" == _exp_0 or "self_class" == _exp_0 or "table" == _exp_0 then + return true + elseif "chain" == _exp_0 then + return chain_assignable[ntype(node[#node])] + else + return false + end + end +end local value_is_singular value_is_singular = function(node) if type(node) ~= "table" then @@ -323,6 +344,7 @@ return { build = build, is_value = is_value, is_slice = is_slice, + is_assignable = is_assignable, manual_return = manual_return, cascading = cascading, value_is_singular = value_is_singular, diff --git a/moonscript/types.moon b/moonscript/types.moon index 99cd54c7..d2e08fce 100644 --- a/moonscript/types.moon +++ b/moonscript/types.moon @@ -52,6 +52,20 @@ is_value = (stm) -> compile.Block\is_value(stm) or transform.Value\can_transform stm +-- determines if node is able to be on left side of assignment +is_assignable = do + chain_assignable = { index: true, dot: true, slice: true } + + (node) -> + return false if node == "..." + switch ntype node + when "ref", "self", "value", "self_class", "table" + true + when "chain" + chain_assignable[ntype node[#node]] + else + false + -- is this expression a single term that can sit next to a binary operator -- without parentheses changing its meaning value_is_singular = (node) -> @@ -200,9 +214,8 @@ smart_node = (node) -> NOOP = {"noop"} { - :ntype, :smart_node, :build, :is_value, :is_slice, :manual_return, - :cascading, :value_is_singular, + :ntype, :smart_node, :build, :is_value, :is_slice, :is_assignable, + :manual_return, :cascading, :value_is_singular, :value_can_be_statement, :mtype, :terminating :NOOP } - diff --git a/moonscript/util.lua b/moonscript/util.lua index dbb1b437..93bfdde6 100644 --- a/moonscript/util.lua +++ b/moonscript/util.lua @@ -105,7 +105,7 @@ dump = function(what) if type(what.__class) == "table" and type(what.__class.__name) == "string" then class_name = "<" .. tostring(what.__class.__name) .. ">" end - return tostring(class_name or "") .. "{\n" .. concat(lines) .. (" "):rep((depth - 1) * 4) .. "}\n" + return (tostring(class_name or "") .. "{\n") .. concat(lines) .. (" "):rep((depth - 1) * 4) .. "}\n" else return tostring(what) .. "\n" end diff --git a/spec/compile_error_spec.moon b/spec/compile_error_spec.moon index c009e9aa..f9f957c7 100644 --- a/spec/compile_error_spec.moon +++ b/spec/compile_error_spec.moon @@ -48,6 +48,16 @@ describe "compile errors", -> 2 } + { + "destructuring into a function call" + unindent [[ + print "hello" + {foo!} = thing + ]] + "Can't destructure into chain ending in call" + 2 + } + { "continue outside of loop" unindent [[ diff --git a/spec/inputs/destructure.moon b/spec/inputs/destructure.moon index 34acdb76..7da93e82 100644 --- a/spec/inputs/destructure.moon +++ b/spec/inputs/destructure.moon @@ -137,3 +137,7 @@ grab = (...) -> {:negated} = not thing {:len} = #thing + +-- assignable non-name targets + +{x: obj.a, y: obj["b"], z: @prop, w: @@cls_prop} = t diff --git a/spec/outputs/destructure.lua b/spec/outputs/destructure.lua index eab1dff1..1ce745cf 100644 --- a/spec/outputs/destructure.lua +++ b/spec/outputs/destructure.lua @@ -307,4 +307,5 @@ local len do local _obj_0 = #thing len = _obj_0.len -end \ No newline at end of file +end +obj.a, obj["b"], self.prop, self.__class.cls_prop = t.x, t.y, t.z, t.w \ No newline at end of file From 95b07e6ec1f480fc41f7054f3e9d8a57e5a0b6a3 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 24 Jul 2026 15:29:11 -0700 Subject: [PATCH 538/554] fixes #448 --- moonscript/parse/util.lua | 2 +- moonscript/parse/util.moon | 4 +++- spec/compile_error_spec.moon | 14 +++++++++++++- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/moonscript/parse/util.lua b/moonscript/parse/util.lua index fcde7db0..8f29241b 100644 --- a/moonscript/parse/util.lua +++ b/moonscript/parse/util.lua @@ -201,7 +201,7 @@ simple_string = function(delim, allow_interpolation) local inner = P("\\" .. tostring(delim)) + "\\\\" + (1 - P(delim)) if allow_interpolation then local interp = symx('#{') * V("Exp") * sym('}') - inner = (C((inner - interp) ^ 1) + interp / mark("interpolate")) ^ 0 + inner = (C((inner - symx('#{')) ^ 1) + interp / mark("interpolate")) ^ 0 else inner = C(inner ^ 0) end diff --git a/moonscript/parse/util.moon b/moonscript/parse/util.moon index e921645d..7ff72820 100644 --- a/moonscript/parse/util.moon +++ b/moonscript/parse/util.moon @@ -144,7 +144,9 @@ simple_string = (delim, allow_interpolation) -> inner = if allow_interpolation interp = symx'#{' * V"Exp" * sym'}' - (C((inner - interp)^1) + interp / mark"interpolate")^0 + -- string content stops at every #{ so a malformed interpolation fails + -- the parse instead of falling through to literal text + (C((inner - symx'#{')^1) + interp / mark"interpolate")^0 else C inner^0 diff --git a/spec/compile_error_spec.moon b/spec/compile_error_spec.moon index f9f957c7..5b016ad4 100644 --- a/spec/compile_error_spec.moon +++ b/spec/compile_error_spec.moon @@ -3,7 +3,7 @@ import with_dev, unindent from require "spec.helpers" -- tests the user facing compile errors triggered by invalid code, including -- the source position they point at describe "compile errors", -> - local to_error + local to_error, parse_fails with_dev -> parse = require "moonscript.parse" @@ -16,6 +16,11 @@ describe "compile errors", -> assert.is_nil code, "expected compile to fail" err, pos and pos_to_line str, pos + parse_fails = (str) -> + tree, err = parse.string str + assert.is_nil tree, "expected parse to fail: #{str}" + assert.truthy err + for {name, code_str, expected_msg, expected_line} in *{ { "short-colon stub outside of with" @@ -72,3 +77,10 @@ describe "compile errors", -> err, line = to_error code_str assert.same expected_msg, err assert.same expected_line, line + + -- a malformed interpolation must fail the parse instead of falling + -- through to literal string content + it "invalid string interpolation fails to parse", -> + parse_fails [[x = "one #{three ..} two"]] + parse_fails [[x = "abc#{"]] + parse_fails [[x = "#{}"]] From e06a23750adcf8628d363f54b047f121fe695db7 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 24 Jul 2026 15:53:42 -0700 Subject: [PATCH 539/554] fix root block regression that broke linter, basic linter test --- moonscript/cmd/lint.lua | 6 +----- moonscript/cmd/lint.moon | 5 +---- moonscript/compile.lua | 2 +- moonscript/compile.moon | 2 +- spec/lint_spec.moon | 21 +++++++++++++++++++++ 5 files changed, 25 insertions(+), 11 deletions(-) create mode 100644 spec/lint_spec.moon diff --git a/moonscript/cmd/lint.lua b/moonscript/cmd/lint.lua index 67805253..88f4e4e6 100644 --- a/moonscript/cmd/lint.lua +++ b/moonscript/cmd/lint.lua @@ -105,7 +105,7 @@ do local _des_0 = tuples[_index_0] local pos, names pos, names = _des_0[1], _des_0[2] - insert(self:get_root_block().lint_errors, { + insert(self.root.lint_errors, { "assigned but unused " .. tostring(table.concat((function() local _accum_0 = { } local _len_0 = 1 @@ -129,7 +129,6 @@ do local _with_0 = _class_0.__parent.__base.block(self, ...) _with_0.block = self.block _with_0.render = self.render - _with_0.get_root_block = self.get_root_block _with_0.lint_check_unused = self.lint_check_unused _with_0.lint_mark_used = self.lint_mark_used _with_0.value_compilers = self.value_compilers @@ -146,9 +145,6 @@ do whitelist_globals = default_whitelist end _class_0.__parent.__init(self, ...) - self.get_root_block = function() - return self - end self.lint_errors = { } local vc = self.value_compilers self.value_compilers = setmetatable({ diff --git a/moonscript/cmd/lint.moon b/moonscript/cmd/lint.moon index 043eb2cf..48d4433c 100644 --- a/moonscript/cmd/lint.moon +++ b/moonscript/cmd/lint.moon @@ -55,8 +55,6 @@ default_whitelist = Set { class LinterBlock extends Block new: (whitelist_globals=default_whitelist, ...) => super ... - @get_root_block = -> @ - @lint_errors = {} vc = @value_compilers @@ -117,7 +115,7 @@ class LinterBlock extends Block table.sort tuples, (a,b) -> a[1] < b[1] for {pos, names} in *tuples - insert @get_root_block!.lint_errors, { + insert @root.lint_errors, { "assigned but unused #{table.concat ["`#{n}`" for n in *names], ", "}" pos } @@ -131,7 +129,6 @@ class LinterBlock extends Block with super ... .block = @block .render = @render - .get_root_block = @get_root_block .lint_check_unused = @lint_check_unused .lint_mark_used = @lint_mark_used .value_compilers = @value_compilers diff --git a/moonscript/compile.lua b/moonscript/compile.lua index ff1cbc0e..d295761f 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -576,6 +576,7 @@ do __index = self.parent._state }) else + self.root = self self.indent = 0 end end, @@ -618,7 +619,6 @@ do _class_0 = setmetatable({ __init = function(self, options) self.options = options - self.root = self return _class_0.__parent.__init(self) end, __base = _base_0, diff --git a/moonscript/compile.moon b/moonscript/compile.moon index 2780de9b..eb16d14b 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -186,6 +186,7 @@ class Block @indent = @parent.indent + 1 setmetatable @_state, { __index: @parent._state } else + @root = self @indent = 0 set: (name, value) => @@ -398,7 +399,6 @@ class Block class RootBlock extends Block new: (@options) => - @root = self super! __tostring: => "RootBlock<>" diff --git a/spec/lint_spec.moon b/spec/lint_spec.moon new file mode 100644 index 00000000..17b70b5b --- /dev/null +++ b/spec/lint_spec.moon @@ -0,0 +1,21 @@ +import with_dev, unindent from require "spec.helpers" + +describe "linter", -> + local lint + + with_dev -> + lint = require "moonscript.cmd.lint" + + it "reports unused assignments in nested blocks", -> + code = unindent [[ + if true + unused = 1 + ]] + + assert.same unindent([[ + string input + + line 2: assigned but unused `unused` + ==================================== + > unused = 1 + ]]), lint.lint_code code From e80f6e4c9ef3742a9da6cbfaf019da7ecb454a4c Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 24 Jul 2026 18:35:16 -0700 Subject: [PATCH 540/554] first pass at argument destructuring #424 --- moonscript/compile/value.lua | 11 +++- moonscript/compile/value.moon | 15 ++++- moonscript/parse.lua | 2 +- moonscript/parse.moon | 2 +- moonscript/transform/destructure.lua | 34 +++++++++-- moonscript/transform/destructure.moon | 19 ++++-- moonscript/transform/value.lua | 18 ++++++ moonscript/transform/value.moon | 16 +++++ spec/compile_error_spec.moon | 21 +++++++ spec/destructure_spec.moon | 63 ++++++++++++++++++++ spec/inputs/destructure.moon | 24 ++++++++ spec/outputs/destructure.lua | 84 ++++++++++++++++++++++++++- 12 files changed, 291 insertions(+), 18 deletions(-) diff --git a/moonscript/compile/value.lua b/moonscript/compile/value.lua index f475a940..30986551 100644 --- a/moonscript/compile/value.lua +++ b/moonscript/compile/value.lua @@ -251,6 +251,7 @@ return { local args, whitelist, arrow, block = unpack(node, 2) local default_args = { } local self_args = { } + local fn_block = self:block() local arg_names do local _accum_0 = { } @@ -260,6 +261,8 @@ return { local name, default_value = unpack(arg) if type(name) == "string" then name = name + elseif name[1] == "temp_name" then + name = name:get_name(fn_block, false) else if name[1] == "self" or name[1] == "self_class" then insert(self_args, name) @@ -279,7 +282,7 @@ return { insert(arg_names, 1, "self") end do - local _with_0 = self:block() + local _with_0 = fn_block _with_0.header = "function(" .. concat(arg_names, ", ") .. ")" if #whitelist > 0 then _with_0:whitelist_names(whitelist) @@ -292,7 +295,11 @@ return { local default = default_args[_index_0] local name, value = unpack(default) if type(name) == "table" then - name = name[2] + if name[1] == "temp_name" then + name = name:get_name(fn_block) + else + name = name[2] + end end _with_0:stm({ 'if', diff --git a/moonscript/compile/value.moon b/moonscript/compile/value.moon index 5d2aaf90..ac84fbe5 100644 --- a/moonscript/compile/value.moon +++ b/moonscript/compile/value.moon @@ -160,10 +160,17 @@ exp_precedence = (node) -> default_args = {} self_args = {} + + fn_block = @block! + arg_names = for arg in *args name, default_value = unpack arg name = if type(name) == "string" name + elseif name[1] == "temp_name" + -- a destructuring arg holds a proxy, resolve it in the function's + -- scope so the header and the unpacking assign agree on the name + name\get_name fn_block, false else if name[1] == "self" or name[1] == "self_class" insert self_args, name @@ -174,7 +181,7 @@ exp_precedence = (node) -> if arrow == "fat" insert arg_names, 1, "self" - with @block! + with fn_block .header = "function("..concat(arg_names, ", ")..")" if #whitelist > 0 @@ -184,7 +191,11 @@ exp_precedence = (node) -> for default in *default_args name, value = unpack default - name = name[2] if type(name) == "table" + if type(name) == "table" + name = if name[1] == "temp_name" + name\get_name fn_block + else + name[2] \stm { 'if', {'exp', {"ref", name}, '==', 'nil'}, { {'assign', {name}, {value}} diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 5dd1540d..6734eb3c 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -189,7 +189,7 @@ local build_grammar = wrap_env(debug_grammar, function(root) KeyValueLine = CheckIndent * KeyValueList * sym(",") ^ -1, FnArgsDef = sym("(") * White * Ct(FnArgDefList ^ -1) * (key("using") * Ct(NameList + Space * "nil") + Ct("")) * White * sym(")") + Ct("") * Ct(""), FnArgDefList = FnArgDef * ((sym(",") + Break) * White * FnArgDef) ^ 0 * ((sym(",") + Break) * White * Ct(VarArg)) ^ 0 + Ct(VarArg), - FnArgDef = Ct((Name + SelfName) * (sym("=") * Exp) ^ -1), + FnArgDef = Ct((Name + SelfName + TableLit) * (sym("=") * Exp) ^ -1), FunLit = FnArgsDef * (sym("->") * Cc("slim") + sym("=>") * Cc("fat")) * (Body + Ct("")) / mark("fndef"), NameList = Name * (sym(",") * Name) ^ 0, NameOrDestructure = Name + TableLit, diff --git a/moonscript/parse.moon b/moonscript/parse.moon index a556ce3c..f9ae314c 100644 --- a/moonscript/parse.moon +++ b/moonscript/parse.moon @@ -297,7 +297,7 @@ build_grammar = wrap_env debug_grammar, (root) -> White * sym")" + Ct"" * Ct"" FnArgDefList: FnArgDef * ((sym"," + Break) * White * FnArgDef)^0 * ((sym"," + Break) * White * Ct(VarArg))^0 + Ct(VarArg) - FnArgDef: Ct((Name + SelfName) * (sym"=" * Exp)^-1) + FnArgDef: Ct((Name + SelfName + TableLit) * (sym"=" * Exp)^-1) FunLit: FnArgsDef * (sym"->" * Cc"slim" + sym"=>" * Cc"fat") * diff --git a/moonscript/transform/destructure.lua b/moonscript/transform/destructure.lua index 889ddac4..acdaa346 100644 --- a/moonscript/transform/destructure.lua +++ b/moonscript/transform/destructure.lua @@ -148,7 +148,7 @@ chainable_receiver = function(node) end end local build_assign -build_assign = function(scope, destruct_literal, receiver) +build_assign = function(scope, destruct_literal, receiver, opts) assert(receiver, "attempting to build destructure assign with no receiver") local extracted_names = extract_assign_names(destruct_literal) local names = { } @@ -186,13 +186,35 @@ build_assign = function(scope, destruct_literal, receiver) end insert(values, chain) end - return build.group({ - { + local group = { } + if opts and opts.shadow then + local shadow_names + do + local _accum_0 = { } + local _len_0 = 1 + for _index_0 = 1, #names do + local name = names[_index_0] + if ntype(name) == "ref" or type(name) == "string" then + _accum_0[_len_0] = name + _len_0 = _len_0 + 1 + end + end + shadow_names = _accum_0 + end + if next(shadow_names) then + insert(group, { + "declare_with_shadows", + shadow_names + }) + end + else + insert(group, { "declare", names - }, - inner - }) + }) + end + insert(group, inner) + return build.group(group) end local split_assign split_assign = function(scope, assign) diff --git a/moonscript/transform/destructure.moon b/moonscript/transform/destructure.moon index 287213ce..3ac34754 100644 --- a/moonscript/transform/destructure.moon +++ b/moonscript/transform/destructure.moon @@ -92,7 +92,7 @@ chainable_receiver = (node) -> else false -build_assign = (scope, destruct_literal, receiver) -> +build_assign = (scope, destruct_literal, receiver, opts) -> assert receiver, "attempting to build destructure assign with no receiver" extracted_names = extract_assign_names destruct_literal @@ -119,10 +119,19 @@ build_assign = (scope, destruct_literal, receiver) -> "nil" insert values, chain - build.group { - {"declare", names} - inner - } + group = {} + + if opts and opts.shadow + -- force new locals so the targets never assign to an enclosing scope, + -- only plain names can be declared (chain and self targets can't) + shadow_names = [name for name in *names when ntype(name) == "ref" or type(name) == "string"] + if next shadow_names + insert group, {"declare_with_shadows", shadow_names} + else + insert group, {"declare", names} + + insert group, inner + build.group group -- applies to destructuring to a assign node split_assign = (scope, assign) -> diff --git a/moonscript/transform/value.lua b/moonscript/transform/value.lua index a2ad90bd..a582586d 100644 --- a/moonscript/transform/value.lua +++ b/moonscript/transform/value.lua @@ -23,6 +23,7 @@ do end local construct_comprehension construct_comprehension = require("moonscript.transform.comprehension").construct_comprehension +local destructure = require("moonscript.transform.destructure") local insert insert = table.insert local unpack @@ -137,6 +138,23 @@ return Transformer({ fndef = function(self, node) smart_node(node) node.body = transform_last_stm(node.body, implicitly_return(self)) + local destructures + local _list_0 = node.args + for _index_0 = 1, #_list_0 do + local arg = _list_0[_index_0] + if ntype(arg[1]) == "table" then + local proxy = NameProxy("arg") + destructures = destructures or { } + insert(destructures, destructure.build_assign(self, arg[1], proxy, { + shadow = true + })) + arg[1] = proxy + end + end + if destructures then + insert(destructures, build.group(node.body)) + node.body = destructures + end return node end, ["if"] = function(self, node) diff --git a/moonscript/transform/value.moon b/moonscript/transform/value.moon index f84ff67c..0bbb20cf 100644 --- a/moonscript/transform/value.moon +++ b/moonscript/transform/value.moon @@ -9,6 +9,7 @@ import user_error from require "moonscript.errors" import transform_last_stm, implicitly_return, chain_is_stub, has_varargs from require "moonscript.transform.statements" import construct_comprehension from require "moonscript.transform.comprehension" +destructure = require "moonscript.transform.destructure" import insert from table import unpack from require "moonscript.util" @@ -84,6 +85,21 @@ Transformer { fndef: (node) => smart_node node node.body = transform_last_stm node.body, implicitly_return self + + -- destructuring args receive a temporary name that is unpacked at the + -- top of the body + local destructures + for arg in *node.args + if ntype(arg[1]) == "table" + proxy = NameProxy "arg" + destructures or= {} + insert destructures, destructure.build_assign @, arg[1], proxy, shadow: true + arg[1] = proxy + + if destructures + insert destructures, build.group node.body + node.body = destructures + node if: (node) => diff --git a/spec/compile_error_spec.moon b/spec/compile_error_spec.moon index 5b016ad4..ebb551e4 100644 --- a/spec/compile_error_spec.moon +++ b/spec/compile_error_spec.moon @@ -63,6 +63,27 @@ describe "compile errors", -> 2 } + { + "destructuring function argument into call" + unindent [[ + print "hello" + f = ({foo!}) -> foo + ]] + "Can't destructure into chain ending in call" + 2 + } + + { + "destructuring function argument into invalid value" + unindent [[ + print "hello" + print "world" + f = ({1}) -> nil + ]] + "Can't destructure value of type: number" + 3 + } + { "continue outside of loop" unindent [[ diff --git a/spec/destructure_spec.moon b/spec/destructure_spec.moon index fe300425..425ef0ab 100644 --- a/spec/destructure_spec.moon +++ b/spec/destructure_spec.moon @@ -30,3 +30,66 @@ describe "destructure", -> assert.same street, "Via Roma 42R" assert.same city, "Bellagio, Italy 22021" + +-- argument destructuring is new syntax, so sources are compiled with the dev +-- compiler at runtime instead of being written directly in this file +describe "function argument destructure", -> + import with_dev, unindent from require "spec.helpers" + + local run + + with_dev -> + parse = require "moonscript.parse" + compile = require "moonscript.compile" + + run = (str) -> + tree = assert parse.string str + code, err = compile.tree tree + assert code, err + chunk = assert (loadstring or load) code + chunk! + + it "unpacks fields", -> + result = run unindent [[ + f = ({:a, :b, :c}) -> a + b + c + return f {a: 1, b: 2, c: 3} + ]] + assert.same 6, result + + it "unpacks multiple table arguments", -> + result = run unindent [[ + dot = ({x: x1, y: y1}, {x: x2, y: y2}) -> x1 * x2 + y1 * y2 + return dot {x: 1, y: 2}, {x: 3, y: 4} + ]] + assert.same 11, result + + it "applies default value", -> + result = run unindent [[ + f = ({:a, :b} = {a: 1, b: 2}) -> a + b + return {f!, f {a: 10, b: 20}} + ]] + assert.same {3, 30}, result + + it "shadows outer variable instead of assigning it", -> + result = run unindent [[ + x = "outer" + f = ({:x}) -> x + inner = f {x: "inner"} + return {inner, x} + ]] + assert.same {"inner", "outer"}, result + + it "assigns self fields with fat arrow", -> + result = run unindent [[ + obj = {total: 10} + obj.add = ({:count}) => @total + count + return obj\add {count: 5} + ]] + assert.same 15, result + + it "preserves surrounding args and varargs", -> + result = run unindent [[ + f = (first, {:mid}, ...) -> {first, mid, select "#", ...} + return f "a", {mid: "b"}, "x", "y" + ]] + assert.same {"a", "b", 2}, result diff --git a/spec/inputs/destructure.moon b/spec/inputs/destructure.moon index 7da93e82..6cc7d974 100644 --- a/spec/inputs/destructure.moon +++ b/spec/inputs/destructure.moon @@ -141,3 +141,27 @@ grab = (...) -> -- assignable non-name targets {x: obj.a, y: obj["b"], z: @prop, w: @@cls_prop} = t + +-- destructuring function arguments + +basic = ({:a, :b}) -> a + b + +two = ({x: x1, y: y1}, {x: x2, y: y2}) -> x1 * x2 + y1 * y2 + +with_default = ({:a, :b} = {a: 1, b: 2}) -> a + b + +nested = ({pos: {:x, :y}, [1]: first}) -> x + y + first + +positional = ({first, second}) -> first .. second + +mixed = (name, {:width, :height}, rest=1, ...) -> + print name, width, height, rest, ... + +bound = ({:count}) => @total + count + +class Point + new: ({x: @x, y: @y}) => + +-- outer local is shadowed, not assigned +shadowed = "outer" +shadow_fn = ({:shadowed}) -> shadowed diff --git a/spec/outputs/destructure.lua b/spec/outputs/destructure.lua index 1ce745cf..d751a340 100644 --- a/spec/outputs/destructure.lua +++ b/spec/outputs/destructure.lua @@ -308,4 +308,86 @@ do local _obj_0 = #thing len = _obj_0.len end -obj.a, obj["b"], self.prop, self.__class.cls_prop = t.x, t.y, t.z, t.w \ No newline at end of file +obj.a, obj["b"], self.prop, self.__class.cls_prop = t.x, t.y, t.z, t.w +local basic +basic = function(_arg_0) + local a, b + a, b = _arg_0.a, _arg_0.b + return a + b +end +local two +two = function(_arg_0, _arg_1) + local x1, y1 + x1, y1 = _arg_0.x, _arg_0.y + local x2, y2 + x2, y2 = _arg_1.x, _arg_1.y + return x1 * x2 + y1 * y2 +end +local with_default +with_default = function(_arg_0) + if _arg_0 == nil then + _arg_0 = { + a = 1, + b = 2 + } + end + local a, b + a, b = _arg_0.a, _arg_0.b + return a + b +end +local nested +nested = function(_arg_0) + local x, y, first + x, y, first = _arg_0.pos.x, _arg_0.pos.y, _arg_0[1] + return x + y + first +end +local positional +positional = function(_arg_0) + local first, second + first, second = _arg_0[1], _arg_0[2] + return first .. second +end +local mixed +mixed = function(name, _arg_0, rest, ...) + if rest == nil then + rest = 1 + end + local width, height + width, height = _arg_0.width, _arg_0.height + return print(name, width, height, rest, ...) +end +local bound +bound = function(self, _arg_0) + local count + count = _arg_0.count + return self.total + count +end +local Point +do + local _class_0 + local _base_0 = { } + _base_0.__index = _base_0 + _class_0 = setmetatable({ + __init = function(self, _arg_0) + self.x, self.y = _arg_0.x, _arg_0.y + end, + __base = _base_0, + __name = "Point" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + Point = _class_0 +end +local shadowed = "outer" +local shadow_fn +shadow_fn = function(_arg_0) + local shadowed + shadowed = _arg_0.shadowed + return shadowed +end \ No newline at end of file From 3514ee98a97f505f7989935ef92218ad48553993 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Fri, 24 Jul 2026 20:00:13 -0700 Subject: [PATCH 541/554] destructure args in order so that other args can reference it in defaults --- moonscript/compile/value.moon | 4 +- moonscript/transform/value.lua | 147 +++++++++++++++++++++++++++++--- moonscript/transform/value.moon | 81 +++++++++++++++--- spec/compile_error_spec.moon | 50 +++++++++++ spec/destructure_spec.moon | 24 ++++++ spec/inputs/destructure.moon | 4 + spec/outputs/destructure.lua | 17 +++- 7 files changed, 298 insertions(+), 29 deletions(-) diff --git a/moonscript/compile/value.moon b/moonscript/compile/value.moon index ac84fbe5..98715514 100644 --- a/moonscript/compile/value.moon +++ b/moonscript/compile/value.moon @@ -168,8 +168,8 @@ exp_precedence = (node) -> name = if type(name) == "string" name elseif name[1] == "temp_name" - -- a destructuring arg holds a proxy, resolve it in the function's - -- scope so the header and the unpacking assign agree on the name + -- a destructuring arg holds a proxy. put the resolved name into + -- scope immediately or a second proxy would pick the same free name name\get_name fn_block, false else if name[1] == "self" or name[1] == "self_class" diff --git a/moonscript/transform/value.lua b/moonscript/transform/value.lua index a582586d..fa016a95 100644 --- a/moonscript/transform/value.lua +++ b/moonscript/transform/value.lua @@ -138,22 +138,143 @@ return Transformer({ fndef = function(self, node) smart_node(node) node.body = transform_last_stm(node.body, implicitly_return(self)) - local destructures - local _list_0 = node.args - for _index_0 = 1, #_list_0 do - local arg = _list_0[_index_0] + local first_destructure + for i, arg in ipairs(node.args) do if ntype(arg[1]) == "table" then - local proxy = NameProxy("arg") - destructures = destructures or { } - insert(destructures, destructure.build_assign(self, arg[1], proxy, { - shadow = true - })) - arg[1] = proxy + first_destructure = i + break end end - if destructures then - insert(destructures, build.group(node.body)) - node.body = destructures + if first_destructure then + local bound_names = { } + if node.arrow == "fat" then + bound_names.self = true + end + local _list_0 = node.args + for _index_0 = 1, #_list_0 do + local arg = _list_0[_index_0] + local _exp_0 = ntype(arg[1]) + if "self" == _exp_0 or "self_class" == _exp_0 then + bound_names[arg[1][2]] = true + elseif "table" == _exp_0 then + local _ = nil + else + if type(arg[1]) == "string" then + bound_names[arg[1]] = true + end + end + end + local seen_targets = { } + local _list_1 = node.args + for _index_0 = 1, #_list_1 do + local _continue_0 = false + repeat + local arg = _list_1[_index_0] + if not (ntype(arg[1]) == "table") then + _continue_0 = true + break + end + local targets + do + local _accum_0 = { } + local _len_0 = 1 + local _list_2 = destructure.extract_assign_names(arg[1]) + for _index_1 = 1, #_list_2 do + local _des_0 = _list_2[_index_1] + local t + t = _des_0[1] + if ntype(t) == "ref" then + _accum_0[_len_0] = t + _len_0 = _len_0 + 1 + end + end + targets = _accum_0 + end + for _index_1 = 1, #targets do + local target = targets[_index_1] + local name = target[2] + if bound_names[name] or seen_targets[name] then + user_error("Can't destructure into '" .. tostring(name) .. "': name is bound by another parameter", target[-1]) + end + end + for _index_1 = 1, #targets do + local target = targets[_index_1] + seen_targets[target[2]] = true + end + _continue_0 = true + until true + if not _continue_0 then + break + end + end + local default_check + default_check = function(name, value) + return { + "if", + { + "exp", + name, + "==", + "nil" + }, + { + { + "assign", + { + name + }, + { + value + } + } + } + } + end + local prelude = { } + for i = first_destructure, #node.args do + local arg = node.args[i] + local name, default_value = arg[1], arg[2] + local _exp_0 = ntype(name) + if "table" == _exp_0 then + local proxy = NameProxy("arg") + if default_value then + insert(prelude, default_check(proxy, default_value)) + end + insert(prelude, destructure.build_assign(self, name, proxy, { + shadow = true + })) + node.args[i] = { + proxy + } + elseif "self" == _exp_0 or "self_class" == _exp_0 then + local raw_name = name[2] + if default_value then + insert(prelude, default_check({ + "ref", + raw_name + }, default_value)) + end + insert(prelude, build.assign_one(name, { + "ref", + raw_name + })) + node.args[i] = { + raw_name + } + else + if default_value then + insert(prelude, default_check({ + "ref", + name + }, default_value)) + node.args[i] = { + name + } + end + end + end + insert(prelude, build.group(node.body)) + node.body = prelude end return node end, diff --git a/moonscript/transform/value.moon b/moonscript/transform/value.moon index 0bbb20cf..74f4956e 100644 --- a/moonscript/transform/value.moon +++ b/moonscript/transform/value.moon @@ -86,19 +86,76 @@ Transformer { smart_node node node.body = transform_last_stm node.body, implicitly_return self - -- destructuring args receive a temporary name that is unpacked at the - -- top of the body - local destructures - for arg in *node.args + -- from the first destructuring arg onward, argument initialization + -- (default checks, self assigns, unpacking) moves into the body in left + -- to right order, so a later default can reference an earlier + -- destructured name: + -- f = ({:a}, b = a) -> b + -- earlier args stay on the compiler's default handling, keeping output + -- for functions without destructuring unchanged + local first_destructure + for i, arg in ipairs node.args if ntype(arg[1]) == "table" - proxy = NameProxy "arg" - destructures or= {} - insert destructures, destructure.build_assign @, arg[1], proxy, shadow: true - arg[1] = proxy - - if destructures - insert destructures, build.group node.body - node.body = destructures + first_destructure = i + break + + if first_destructure + -- a destructured name always shadows at the top of the body, so a + -- later parameter of the same name could never be seen. reject the + -- duplicate instead of silently breaking later-parameter-wins + bound_names = {} + -- fat arrow binds self as an implicit first parameter + bound_names.self = true if node.arrow == "fat" + for arg in *node.args + switch ntype arg[1] + when "self", "self_class" + bound_names[arg[1][2]] = true + when "table" + nil + else + bound_names[arg[1]] = true if type(arg[1]) == "string" + + seen_targets = {} + for arg in *node.args + continue unless ntype(arg[1]) == "table" + targets = [t for {t} in *destructure.extract_assign_names arg[1] when ntype(t) == "ref"] + + for target in *targets + name = target[2] + if bound_names[name] or seen_targets[name] + user_error "Can't destructure into '#{name}': name is bound by another parameter", target[-1] + + for target in *targets + seen_targets[target[2]] = true + + default_check = (name, value) -> + {"if", {"exp", name, "==", "nil"}, {{"assign", {name}, {value}}}} + + prelude = {} + for i=first_destructure, #node.args + arg = node.args[i] + name, default_value = arg[1], arg[2] + + switch ntype name + when "table" + proxy = NameProxy "arg" + if default_value + insert prelude, default_check proxy, default_value + insert prelude, destructure.build_assign @, name, proxy, shadow: true + node.args[i] = {proxy} + when "self", "self_class" + raw_name = name[2] + if default_value + insert prelude, default_check {"ref", raw_name}, default_value + insert prelude, build.assign_one name, {"ref", raw_name} + node.args[i] = {raw_name} + else + if default_value + insert prelude, default_check {"ref", name}, default_value + node.args[i] = {name} + + insert prelude, build.group node.body + node.body = prelude node diff --git a/spec/compile_error_spec.moon b/spec/compile_error_spec.moon index ebb551e4..870663cf 100644 --- a/spec/compile_error_spec.moon +++ b/spec/compile_error_spec.moon @@ -84,6 +84,56 @@ describe "compile errors", -> 3 } + { + "destructured parameter followed by parameter of same name" + unindent [[ + print "hello" + f = ({:a}, a) -> a + ]] + "Can't destructure into 'a': name is bound by another parameter" + 2 + } + + { + "destructured parameter preceded by parameter of same name" + unindent [[ + print "hello" + f = (a, {:a}) -> a + ]] + "Can't destructure into 'a': name is bound by another parameter" + 2 + } + + { + "destructured parameter followed by self parameter of same name" + unindent [[ + print "hello" + f = ({:a}, @a) => a + ]] + "Can't destructure into 'a': name is bound by another parameter" + 2 + } + + { + "destructured self parameter in fat arrow" + unindent [[ + print "hello" + f = ({:self}) => @x + ]] + "Can't destructure into 'self': name is bound by another parameter" + 2 + } + + { + "two destructured parameters binding same name" + unindent [[ + print "hello" + f = ({:a}, {a: a}) -> a + ]] + "Can't destructure into 'a': name is bound by another parameter" + 2 + } + { "continue outside of loop" unindent [[ diff --git a/spec/destructure_spec.moon b/spec/destructure_spec.moon index 425ef0ab..bd3bce98 100644 --- a/spec/destructure_spec.moon +++ b/spec/destructure_spec.moon @@ -93,3 +93,27 @@ describe "function argument destructure", -> return f "a", {mid: "b"}, "x", "y" ]] assert.same {"a", "b", 2}, result + + it "later defaults see earlier destructured names", -> + result = run unindent [[ + a = "outer" + f = ({:a}, b = a) -> b + return f {a: 42} + ]] + assert.same 42, result + + it "lowers self assigns after destructure in order", -> + result = run unindent [[ + obj = {} + obj.set = ({:base}, @x = base * 2) => @x + first = obj\set {base: 3} + return {first, obj.x, obj\set({base: 3}, 99)} + ]] + assert.same {6, 6, 99}, result + + it "chains destructure defaults left to right", -> + result = run unindent [[ + f = ({:a} = {a: 1}, {:b} = {b: a + 10}) -> {a, b} + return f! + ]] + assert.same {1, 11}, result diff --git a/spec/inputs/destructure.moon b/spec/inputs/destructure.moon index 6cc7d974..2320709c 100644 --- a/spec/inputs/destructure.moon +++ b/spec/inputs/destructure.moon @@ -165,3 +165,7 @@ class Point -- outer local is shadowed, not assigned shadowed = "outer" shadow_fn = ({:shadowed}) -> shadowed + +-- later defaults see names bound by earlier destructuring args +ordered = ({:a}, b = a, @c = b) => + a + b + @c diff --git a/spec/outputs/destructure.lua b/spec/outputs/destructure.lua index d751a340..2f44e329 100644 --- a/spec/outputs/destructure.lua +++ b/spec/outputs/destructure.lua @@ -349,11 +349,11 @@ positional = function(_arg_0) end local mixed mixed = function(name, _arg_0, rest, ...) + local width, height + width, height = _arg_0.width, _arg_0.height if rest == nil then rest = 1 end - local width, height - width, height = _arg_0.width, _arg_0.height return print(name, width, height, rest, ...) end local bound @@ -390,4 +390,17 @@ shadow_fn = function(_arg_0) local shadowed shadowed = _arg_0.shadowed return shadowed +end +local ordered +ordered = function(self, _arg_0, b, c) + local a + a = _arg_0.a + if b == nil then + b = a + end + if c == nil then + c = b + end + self.c = c + return a + b + self.c end \ No newline at end of file From 9802d35659047b7fd649dd0269673578768da8c5 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 25 Jul 2026 07:55:20 -0700 Subject: [PATCH 542/554] write a "declare_constants" node for imported names, add const resassignment checking in linter This does not affect the compiler or output in anyway, just adds new linting rule. In future moonscripts we'll likely enforce const at compile time, but this lint change is intermediate warning for your existing code --- moonscript/cmd/lint.lua | 15 ++++++ moonscript/cmd/lint.moon | 13 +++++ moonscript/compile.lua | 18 +++++++ moonscript/compile.moon | 16 ++++++ moonscript/compile/statement.lua | 19 ++++++- moonscript/compile/statement.moon | 14 ++++- moonscript/transform/statement.lua | 25 ++++++--- moonscript/transform/statement.moon | 10 +++- spec/inputs/import.moon | 13 +++++ spec/lint_spec.moon | 80 +++++++++++++++++++++++++++++ spec/outputs/import.lua | 35 +++++++++++++ 11 files changed, 244 insertions(+), 14 deletions(-) diff --git a/moonscript/cmd/lint.lua b/moonscript/cmd/lint.lua index 88f4e4e6..90274803 100644 --- a/moonscript/cmd/lint.lua +++ b/moonscript/cmd/lint.lua @@ -174,6 +174,21 @@ do _continue_0 = true break end + local const_name + if type(name) == "string" then + const_name = name + elseif name[1] == "ref" then + const_name = name[2] + end + if const_name then + local binding = block:binding_value(const_name) + if type(binding) == "table" and binding.const then + insert(self.lint_errors, { + "assigning to constant `" .. tostring(const_name) .. "`", + type(name) == "table" and name[-1] or node[-1] or block.root.last_pos + }) + end + end local real_name, is_local = block:extract_assign_name(name) if not (is_local or real_name and not block:has_name(real_name, true)) then _continue_0 = true diff --git a/moonscript/cmd/lint.moon b/moonscript/cmd/lint.moon index 48d4433c..be2e9f24 100644 --- a/moonscript/cmd/lint.moon +++ b/moonscript/cmd/lint.moon @@ -81,6 +81,19 @@ class LinterBlock extends Block if type(name) == "table" and name[1] == "temp_name" continue + const_name = if type(name) == "string" + name + elseif name[1] == "ref" + name[2] + + if const_name + binding = block\binding_value const_name + if type(binding) == "table" and binding.const + insert @lint_errors, { + "assigning to constant `#{const_name}`" + type(name) == "table" and name[-1] or node[-1] or block.root.last_pos + } + real_name, is_local = block\extract_assign_name name -- already defined in some other scope unless is_local or real_name and not block\has_name real_name, true diff --git a/moonscript/compile.lua b/moonscript/compile.lua index d295761f..0dace036 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -346,6 +346,24 @@ do end self._names[name] = value end, + put_fresh_names = function(self, names) + for _index_0 = 1, #names do + local name = names[_index_0] + local real_name = self:extract_assign_name(name) + if real_name then + self:put_name(real_name) + end + end + end, + binding_value = function(self, name) + local val = self._names[name] + if val == nil and self.parent then + if not self._name_whitelist or self._name_whitelist[name] then + return self.parent:binding_value(name) + end + end + return val + end, has_name = function(self, name, skip_exports) if not skip_exports and self:name_exported(name) then return true diff --git a/moonscript/compile.moon b/moonscript/compile.moon index eb16d14b..2ea34c60 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -240,6 +240,22 @@ class Block name = name\get_name self if NameProxy == mtype name @_names[name] = value + -- record names the current construct always binds fresh (loop variables, + -- local statements), so they shadow any binding in an enclosing scope + put_fresh_names: (names) => + for name in *names + real_name = @extract_assign_name name + @put_name real_name if real_name + + -- the value stored for a binding by put_name, following the same scope + -- visibility as has_name. constant bindings store a descriptor table + binding_value: (name) => + val = @_names[name] + if val == nil and @parent + if not @_name_whitelist or @_name_whitelist[name] + return @parent\binding_value name + val + -- Check if a name is defined in the current or any enclosing scope -- skip_exports: ignore names that have been exported using `export` has_name: (name, skip_exports) => diff --git a/moonscript/compile/statement.lua b/moonscript/compile/statement.lua index 3e935e54..66907ce7 100644 --- a/moonscript/compile/statement.lua +++ b/moonscript/compile/statement.lua @@ -11,6 +11,20 @@ return { raw = function(self, node) return self:add(node[2]) end, + declare_constants = function(self, node) + local _list_0 = node[2] + for _index_0 = 1, #_list_0 do + local name = _list_0[_index_0] + if ntype(name) == "ref" then + name = name[2] + end + self:put_name(name, { + const = true, + pos = node[-1] + }) + end + return nil + end, declare = function(self, node) local names = node[2] local undeclared = self:declare(names) @@ -34,6 +48,7 @@ return { declare_with_shadows = function(self, node) local names = node[2] self:declare(names) + self:put_fresh_names(names) do local _with_0 = self:line("local ") _with_0:append_list((function() @@ -158,7 +173,7 @@ return { }), " do") do local _with_0 = self:block(loop) - _with_0:declare({ + _with_0:put_fresh_names({ name }) _with_0:stms(block) @@ -197,7 +212,7 @@ return { return _accum_0 end)(), ",") loop:append(" do") - _with_0:declare(names) + _with_0:put_fresh_names(names) _with_0:stms(block) return _with_0 end diff --git a/moonscript/compile/statement.moon b/moonscript/compile/statement.moon index ac67b7eb..8624f9a7 100644 --- a/moonscript/compile/statement.moon +++ b/moonscript/compile/statement.moon @@ -7,6 +7,14 @@ import unpack from require "moonscript.util" { raw: (node) => @add node[2] + -- tags existing bindings as constant, has no output. only generated by + -- transformations, there is no syntax that produces this statement + declare_constants: (node) => + for name in *node[2] + name = name[2] if ntype(name) == "ref" + @put_name name, const: true, pos: node[-1] + nil + declare: (node) => names = node[2] undeclared = @declare names @@ -18,6 +26,8 @@ import unpack from require "moonscript.util" declare_with_shadows: (node) => names = node[2] @declare names + @put_fresh_names names + with @line "local " \append_list [@name name for name in *names], ", " @@ -87,7 +97,7 @@ import unpack from require "moonscript.util" name, bounds, block = unpack node, 2 loop = @line "for ", @name(name), " = ", @value({"explist", unpack bounds}), " do" with @block loop - \declare {name} + \put_fresh_names {name} \stms block -- for x in y ... @@ -104,7 +114,7 @@ import unpack from require "moonscript.util" loop\append_list [@value exp for exp in *exps], "," loop\append " do" - \declare names + \put_fresh_names names \stms block export: (node) => diff --git a/moonscript/transform/statement.lua b/moonscript/transform/statement.lua index 51e1c399..c6bfeafd 100644 --- a/moonscript/transform/statement.lua +++ b/moonscript/transform/statement.lua @@ -105,7 +105,7 @@ extract_declarations = function(self, body, start, out) stm = self.transform.statement(stm) body[i] = stm local _exp_0 = stm[1] - if "assign" == _exp_0 or "declare" == _exp_0 then + if "assign" == _exp_0 or "declare" == _exp_0 or "declare_constants" == _exp_0 then local _list_0 = stm[2] for _index_0 = 1, #_list_0 do local name = _list_0[_index_0] @@ -444,6 +444,7 @@ return Transformer({ end, import = function(self, node) local names, source = unpack(node, 2) + local dest_names = { } local table_values do local _accum_0 = { } @@ -456,6 +457,7 @@ return Transformer({ else dest_name = name end + insert(dest_names, dest_name) local _value_0 = { { "key_literal", @@ -472,16 +474,23 @@ return Transformer({ "table", table_values } - return { - "assign", + return build.group({ { - dest + "assign", + { + dest + }, + { + source + }, + [-1] = node[-1] }, { - source - }, - [-1] = node[-1] - } + "declare_constants", + dest_names, + [-1] = node[-1] + } + }) end, comprehension = function(self, node, action) local exp, clauses = unpack(node, 2) diff --git a/moonscript/transform/statement.moon b/moonscript/transform/statement.moon index 43059a13..053993b6 100644 --- a/moonscript/transform/statement.moon +++ b/moonscript/transform/statement.moon @@ -58,7 +58,7 @@ extract_declarations = (body=@current_stms, start=@current_stm_i + 1, out={}) => stm = @transform.statement stm body[i] = stm switch stm[1] - when "assign", "declare" + when "assign", "declare", "declare_constants" for name in *stm[2] if ntype(name) == "ref" insert out, name @@ -278,16 +278,22 @@ Transformer { import: (node) => names, source = unpack node, 2 + + dest_names = {} table_values = for name in *names dest_name = if ntype(name) == "colon" name[2] else name + insert dest_names, dest_name {{"key_literal", name}, dest_name} dest = { "table", table_values } - { "assign", {dest}, {source}, [-1]: node[-1] } + build.group { + { "assign", {dest}, {source}, [-1]: node[-1] } + { "declare_constants", dest_names, [-1]: node[-1] } + } comprehension: (node, action) => exp, clauses = unpack node, 2 diff --git a/spec/inputs/import.moon b/spec/inputs/import.moon index d86d7243..9d6e6b4b 100644 --- a/spec/inputs/import.moon +++ b/spec/inputs/import.moon @@ -46,3 +46,16 @@ do c from z + + +-- import name is hoisted by local * +do + local * + use = -> insert "hello" + import insert from table + +-- import inside class body is hoisted for methods +class Pipeline + import insert from table + + add: (...) => insert @, ... diff --git a/spec/lint_spec.moon b/spec/lint_spec.moon index 17b70b5b..22d1dbbc 100644 --- a/spec/lint_spec.moon +++ b/spec/lint_spec.moon @@ -19,3 +19,83 @@ describe "linter", -> ==================================== > unused = 1 ]]), lint.lint_code code + + it "reports assigning to constant import", -> + code = unindent [[ + import insert from table + insert = 5 + ]] + + assert.same unindent([[ + string input + + line 2: assigning to constant `insert` + ====================================== + > insert = 5 + ]]), lint.lint_code code + + it "reports update op on constant import", -> + code = unindent [[ + import count from require "thing" + count += 1 + ]] + + assert.same unindent([[ + string input + + line 2: assigning to constant `count` + ===================================== + > count += 1 + ]]), lint.lint_code code + + it "allows shadowing a constant import", -> + code = unindent [[ + import insert from table + insert {}, 1 + f = (insert) -> insert + g = -> + local insert + insert = 5 + insert + f g! + ]] + + assert.is_nil (lint.lint_code code) + + -- loop variables are fresh locals in every loop form, writing them never + -- touches the enclosing binding + it "allows loop variables shadowing a constant import", -> + code = unindent [[ + import x from table + f = -> x + for x = 1, 2 + x = 3 + f! + for x in ipairs {} + x = 4 + f! + for x in *{1, 2} + x = 5 + f! + ]] + + assert.is_nil (lint.lint_code code) + + -- a repeated import overwrites the existing binding instead of shadowing + -- it, so it counts as a constant write like any other assignment + it "flags a repeated import", -> + code = unindent [[ + import insert from table + insert {}, 1 + do + import insert from require "custom" + insert 2 + ]] + + assert.same unindent([[ + string input + + line 4: assigning to constant `insert` + ======================================= + > import insert from require "custom" + ]]), lint.lint_code code diff --git a/spec/outputs/import.lua b/spec/outputs/import.lua index 4c6520eb..694c9b2e 100644 --- a/spec/outputs/import.lua +++ b/spec/outputs/import.lua @@ -74,4 +74,39 @@ do local _obj_0 = z a, b, c = _obj_0.a, _obj_0.b, _obj_0.c end +end +do + local use, insert + use = function() + return insert("hello") + end + insert = table.insert +end +local Pipeline +do + local _class_0 + local insert + local _base_0 = { + add = function(self, ...) + return insert(self, ...) + end + } + _base_0.__index = _base_0 + _class_0 = setmetatable({ + __init = function() end, + __base = _base_0, + __name = "Pipeline" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + insert = table.insert + Pipeline = _class_0 + return _class_0 end \ No newline at end of file From 9108dffea767f06acec163ae449e8dbb622a4048 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 25 Jul 2026 12:34:30 -0700 Subject: [PATCH 543/554] add overriding import lint --- moonscript/cmd/lint.lua | 54 ++++++++++++++++++++++++----- moonscript/cmd/lint.moon | 36 ++++++++++++++++++- spec/lint_spec.moon | 74 ++++++++++++++++++++++++++++++++++++++-- 3 files changed, 153 insertions(+), 11 deletions(-) diff --git a/moonscript/cmd/lint.lua b/moonscript/cmd/lint.lua index 90274803..d152a7c0 100644 --- a/moonscript/cmd/lint.lua +++ b/moonscript/cmd/lint.lua @@ -4,6 +4,8 @@ local Set Set = require("moonscript.data").Set local Block Block = require("moonscript.compile").Block +local ntype +ntype = require("moonscript.types").ntype local mtype mtype = require("moonscript.util").mtype local default_whitelist = Set({ @@ -126,14 +128,16 @@ do end, block = function(self, ...) do - local _with_0 = _class_0.__parent.__base.block(self, ...) - _with_0.block = self.block - _with_0.render = self.render - _with_0.lint_check_unused = self.lint_check_unused - _with_0.lint_mark_used = self.lint_mark_used - _with_0.value_compilers = self.value_compilers - _with_0.statement_compilers = self.statement_compilers - return _with_0 + local child = _class_0.__parent.__base.block(self, ...) + child.block = self.block + child.render = self.render + child.lint_check_unused = self.lint_check_unused + child.lint_mark_used = self.lint_mark_used + child.value_compilers = self.value_compilers + child.statement_compilers = self.statement_compilers + child.lint_wrap_transform = self.lint_wrap_transform + self:lint_wrap_transform(child) + return child end end } @@ -146,6 +150,40 @@ do end _class_0.__parent.__init(self, ...) self.lint_errors = { } + self.lint_wrap_transform = function(self, block) + local inner = block.transform.statement + local checked_imports = setmetatable({ }, { + __mode = "k" + }) + block.transform.statement = function(node, ...) + local import_node = node + while ntype(import_node) == "transform" do + import_node = import_node[2] + end + if ntype(import_node) == "import" and not checked_imports[import_node] then + checked_imports[import_node] = true + local _list_0 = import_node[2] + for _index_0 = 1, #_list_0 do + local name = _list_0[_index_0] + if ntype(name) == "colon" then + name = name[2] + end + local binding = block:binding_value(name) + if not (type(binding) == "table" and binding.const) then + if binding then + insert(block.root.lint_errors, { + "import overwrites existing binding `" .. tostring(name) .. "`", + import_node[-1] + }) + end + end + end + end + return inner(node, ...) + end + return block + end + self:lint_wrap_transform(self) local vc = self.value_compilers self.value_compilers = setmetatable({ ref = function(block, val) diff --git a/moonscript/cmd/lint.moon b/moonscript/cmd/lint.moon index be2e9f24..8d22d6aa 100644 --- a/moonscript/cmd/lint.moon +++ b/moonscript/cmd/lint.moon @@ -2,6 +2,7 @@ import insert from table import Set from require "moonscript.data" import Block from require "moonscript.compile" +import ntype from require "moonscript.types" import mtype from require "moonscript.util" @@ -57,6 +58,36 @@ class LinterBlock extends Block super ... @lint_errors = {} + @lint_wrap_transform = (block) => + inner = block.transform.statement + checked_imports = setmetatable {}, __mode: "k" + + block.transform.statement = (node, ...) -> + import_node = node + while ntype(import_node) == "transform" + import_node = import_node[2] + + if ntype(import_node) == "import" and not checked_imports[import_node] + checked_imports[import_node] = true + + for name in *import_node[2] + name = name[2] if ntype(name) == "colon" + binding = block\binding_value name + + -- repeated imports are reported by the constant assignment + -- check after the import is lowered + unless type(binding) == "table" and binding.const + if binding + insert block.root.lint_errors, { + "import overwrites existing binding `#{name}`" + import_node[-1] + } + + inner node, ... + block + + @lint_wrap_transform @ + vc = @value_compilers @value_compilers = setmetatable { ref: (block, val) -> @@ -75,6 +106,7 @@ class LinterBlock extends Block @statement_compilers = setmetatable { assign: (block, node) -> names = node[2] + -- extract the names to be declared for name in *names -- don't include autogenerated names @@ -139,13 +171,15 @@ class LinterBlock extends Block block: (...) => - with super ... + with child = super ... .block = @block .render = @render .lint_check_unused = @lint_check_unused .lint_mark_used = @lint_mark_used .value_compilers = @value_compilers .statement_compilers = @statement_compilers + .lint_wrap_transform = @lint_wrap_transform + @lint_wrap_transform child format_lint = (errors, code, header) -> return unless next errors diff --git a/spec/lint_spec.moon b/spec/lint_spec.moon index 22d1dbbc..ce3609a0 100644 --- a/spec/lint_spec.moon +++ b/spec/lint_spec.moon @@ -81,8 +81,78 @@ describe "linter", -> assert.is_nil (lint.lint_code code) - -- a repeated import overwrites the existing binding instead of shadowing - -- it, so it counts as a constant write like any other assignment + -- importing a name bound in an enclosing scope writes that binding + -- instead of creating a local + it "flags import overwriting an enclosing binding", -> + code = unindent [[ + insert = "hello" + f = -> + import insert from table + insert + f! + ]] + + assert.same unindent([[ + string input + + line 3: import overwrites existing binding `insert` + =================================================== + > import insert from table + ]]), lint.lint_code code + + it "flags import overwriting a binding in the same scope", -> + code = unindent [[ + insert = "hello" + import insert from table + insert {}, 1 + ]] + + assert.same unindent([[ + string input + + line 2: import overwrites existing binding `insert` + =================================================== + > import insert from table + ]]), lint.lint_code code + + it "flags a final import overwriting an enclosing binding", -> + code = unindent [[ + insert = "hello" + f = -> + print insert + import insert from table + f! + ]] + + assert.same unindent([[ + string input + + line 4: import overwrites existing binding `insert` + =================================================== + > import insert from table + ]]), lint.lint_code code + + it "flags import inside nested function overwriting a declared local", -> + code = unindent [[ + f = -> + local check_app_version + reload = -> + import check_app_version from require "helpers.api" + print "reloaded" + reload! + check_app_version! + f! + ]] + + assert.same unindent([[ + string input + + line 4: import overwrites existing binding `check_app_version` + ============================================================== + > import check_app_version from require "helpers.api" + ]]), lint.lint_code code + + -- a repeated import writes the existing constant binding it "flags a repeated import", -> code = unindent [[ import insert from table From 26f29d01fb07cb1d97b16231d6aae74947a50759 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 25 Jul 2026 12:55:33 -0700 Subject: [PATCH 544/554] add support for toggling lint stages via cli --- bin/moonc | 42 ++++++++++++++++++++++-- docs/command_line.md | 16 +++++++++ moonscript/cmd/lint.lua | 70 ++++++++++++++++++++++------------------ moonscript/cmd/lint.moon | 50 ++++++++++++++++------------ spec/lint_spec.moon | 26 +++++++++++++++ 5 files changed, 150 insertions(+), 54 deletions(-) diff --git a/bin/moonc b/bin/moonc index 13e101af..50f2943c 100644 --- a/bin/moonc +++ b/bin/moonc @@ -7,6 +7,21 @@ local parser = argparse() parser:flag("-l --lint", "Perform a lint on the file instead of compiling") +-- may be nil when an older moonscript.cmd.lint is loaded from the module path +local all_lint_stages = require("moonscript.cmd.lint").lint_stages + +local lint_stage_opt = parser:option("--lint-stage", + "Limit lint to the given stage name (repeatable)"):count("*") +local exclude_lint_stage_opt = parser:option("--exclude-lint-stage", + "Lint with all stages except the given stage name (repeatable)"):count("*") + +if all_lint_stages then + lint_stage_opt:choices(all_lint_stages) + exclude_lint_stage_opt:choices(all_lint_stages) +end + +parser:mutex(lint_stage_opt, exclude_lint_stage_opt) + parser:flag("-v --version", "Print version"):action(function() require("moonscript.version").print_version() os.exit(0) @@ -39,6 +54,27 @@ end local opts = read_stdin and {} or parser:parse() +-- the list of lint stages to run, nil runs all of them +local lint_stages +do + local included, excluded = opts.lint_stage, opts.exclude_lint_stage + if included and #included > 0 then + lint_stages = included + elseif excluded and #excluded > 0 then + local skip = {} + for _, name in ipairs(excluded) do + skip[name] = true + end + + lint_stages = {} + for _, name in ipairs(all_lint_stages or {}) do + if not skip[name] then + table.insert(lint_stages, name) + end + end + end +end + function log_msg(...) if not opts.p then io.stderr:write(table.concat({...}, " ") .. "\n") @@ -151,7 +187,9 @@ if opts.watch then local handle_file if opts.lint then local lint = require "moonscript.cmd.lint" - handle_file = lint.lint_file + handle_file = function(fname) + return lint.lint_file(fname, lint_stages) + end else handle_file = compile_and_write end @@ -199,7 +237,7 @@ elseif opts.lint then local lint = require "moonscript.cmd.lint" for _, tuple in pairs(files) do local fname = tuple[1] - local res, err = lint.lint_file(fname) + local res, err = lint.lint_file(fname, lint_stages) if res then has_linted_with_error = true io.stderr:write(res .. "\n\n") diff --git a/docs/command_line.md b/docs/command_line.md index f0e5d4b2..7accdf11 100644 --- a/docs/command_line.md +++ b/docs/command_line.md @@ -163,6 +163,22 @@ The linter is compatible with the watch mode (see above) for automatic linting. moonc -l file1.moon file2.moon ``` +The linter's checks are organized into named stages: `global_access`, +`unused`, `constant_assign`, `import_overwrite`. By default every stage is +reported. The `--lint-stage` option limits reporting to the given stage, and +`--exclude-lint-stage` reports every stage except the given one. Both can be +repeated to name multiple stages, and they can not be combined: + +- `global_access` reports references to undeclared global variables. +- `unused` reports local assignments that are never used. +- `constant_assign` reports assignments to constant bindings, such as imports. +- `import_overwrite` reports imports that overwrite existing bindings. + +```bash +moonc -l --lint-stage global_access --lint-stage unused . +moonc -l --exclude-lint-stage import_overwrite . +``` + Like when compiling, you can also pass a directory as a command line argument to recursively process all the `.moon` files. diff --git a/moonscript/cmd/lint.lua b/moonscript/cmd/lint.lua index d152a7c0..1f4a2b8c 100644 --- a/moonscript/cmd/lint.lua +++ b/moonscript/cmd/lint.lua @@ -52,11 +52,27 @@ local default_whitelist = Set({ "true", "false" }) +local lint_stages = { + "global_access", + "unused", + "constant_assign", + "import_overwrite" +} local LinterBlock do local _class_0 local _parent_0 = Block local _base_0 = { + lint_report = function(self, stage, msg, pos) + local root = self.root + if root.lint_stages and not root.lint_stages[stage] then + return + end + return insert(root.lint_errors, { + msg, + pos + }) + end, lint_mark_used = function(self, name) if self.lint_unused_names and self.lint_unused_names[name] then self.lint_unused_names[name] = false @@ -107,19 +123,16 @@ do local _des_0 = tuples[_index_0] local pos, names pos, names = _des_0[1], _des_0[2] - insert(self.root.lint_errors, { - "assigned but unused " .. tostring(table.concat((function() - local _accum_0 = { } - local _len_0 = 1 - for _index_1 = 1, #names do - local n = names[_index_1] - _accum_0[_len_0] = "`" .. tostring(n) .. "`" - _len_0 = _len_0 + 1 - end - return _accum_0 - end)(), ", ")), - pos - }) + self.root:lint_report("unused", "assigned but unused " .. tostring(table.concat((function() + local _accum_0 = { } + local _len_0 = 1 + for _index_1 = 1, #names do + local n = names[_index_1] + _accum_0[_len_0] = "`" .. tostring(n) .. "`" + _len_0 = _len_0 + 1 + end + return _accum_0 + end)(), ", ")), pos) end end, render = function(self, ...) @@ -144,12 +157,15 @@ do _base_0.__index = _base_0 setmetatable(_base_0, _parent_0.__base) _class_0 = setmetatable({ - __init = function(self, whitelist_globals, ...) + __init = function(self, whitelist_globals, stages, ...) if whitelist_globals == nil then whitelist_globals = default_whitelist end _class_0.__parent.__init(self, ...) self.lint_errors = { } + if stages then + self.lint_stages = Set(stages) + end self.lint_wrap_transform = function(self, block) local inner = block.transform.statement local checked_imports = setmetatable({ }, { @@ -171,10 +187,7 @@ do local binding = block:binding_value(name) if not (type(binding) == "table" and binding.const) then if binding then - insert(block.root.lint_errors, { - "import overwrites existing binding `" .. tostring(name) .. "`", - import_node[-1] - }) + block.root:lint_report("import_overwrite", "import overwrites existing binding `" .. tostring(name) .. "`", import_node[-1]) end end end @@ -189,10 +202,7 @@ do ref = function(block, val) local name = val[2] if not (block:has_name(name) or whitelist_globals[name] or name:match("%.")) then - insert(self.lint_errors, { - "accessing global `" .. tostring(name) .. "`", - val[-1] - }) + self:lint_report("global_access", "accessing global `" .. tostring(name) .. "`", val[-1]) end block:lint_mark_used(name) return vc.ref(block, val) @@ -221,10 +231,7 @@ do if const_name then local binding = block:binding_value(const_name) if type(binding) == "table" and binding.const then - insert(self.lint_errors, { - "assigning to constant `" .. tostring(const_name) .. "`", - type(name) == "table" and name[-1] or node[-1] or block.root.last_pos - }) + self:lint_report("constant_assign", "assigning to constant `" .. tostring(const_name) .. "`", type(name) == "table" and name[-1] or node[-1] or block.root.last_pos) end end local real_name, is_local = block:extract_assign_name(name) @@ -345,7 +352,7 @@ do end end local lint_code -lint_code = function(code, name, whitelist_globals) +lint_code = function(code, name, whitelist_globals, stages) if name == nil then name = "string input" end @@ -354,20 +361,21 @@ lint_code = function(code, name, whitelist_globals) if not (tree) then return nil, err end - local scope = LinterBlock(whitelist_globals) + local scope = LinterBlock(whitelist_globals, stages) scope:stms(tree) scope:lint_check_unused() return format_lint(scope.lint_errors, code, name) end local lint_file -lint_file = function(fname) +lint_file = function(fname, stages) local f, err = io.open(fname) if not (f) then return nil, err end - return lint_code(f:read("*a"), fname, whitelist_for_file(fname)) + return lint_code(f:read("*a"), fname, whitelist_for_file(fname), stages) end return { lint_code = lint_code, - lint_file = lint_file + lint_file = lint_file, + lint_stages = lint_stages } diff --git a/moonscript/cmd/lint.moon b/moonscript/cmd/lint.moon index 8d22d6aa..fa5d6000 100644 --- a/moonscript/cmd/lint.moon +++ b/moonscript/cmd/lint.moon @@ -53,11 +53,22 @@ default_whitelist = Set { "false" } +-- the named checks that can be enabled or disabled when linting +lint_stages = { + "global_access" + "unused" + "constant_assign" + "import_overwrite" +} + class LinterBlock extends Block - new: (whitelist_globals=default_whitelist, ...) => + new: (whitelist_globals=default_whitelist, stages, ...) => super ... @lint_errors = {} + if stages + @lint_stages = Set stages + @lint_wrap_transform = (block) => inner = block.transform.statement checked_imports = setmetatable {}, __mode: "k" @@ -78,10 +89,8 @@ class LinterBlock extends Block -- check after the import is lowered unless type(binding) == "table" and binding.const if binding - insert block.root.lint_errors, { - "import overwrites existing binding `#{name}`" - import_node[-1] - } + block.root\lint_report "import_overwrite", + "import overwrites existing binding `#{name}`", import_node[-1] inner node, ... block @@ -93,10 +102,7 @@ class LinterBlock extends Block ref: (block, val) -> name = val[2] unless block\has_name(name) or whitelist_globals[name] or name\match "%." - insert @lint_errors, { - "accessing global `#{name}`" - val[-1] - } + @lint_report "global_access", "accessing global `#{name}`", val[-1] block\lint_mark_used name vc.ref block, val @@ -121,10 +127,8 @@ class LinterBlock extends Block if const_name binding = block\binding_value const_name if type(binding) == "table" and binding.const - insert @lint_errors, { - "assigning to constant `#{const_name}`" + @lint_report "constant_assign", "assigning to constant `#{const_name}`", type(name) == "table" and name[-1] or node[-1] or block.root.last_pos - } real_name, is_local = block\extract_assign_name name -- already defined in some other scope @@ -139,6 +143,12 @@ class LinterBlock extends Block sc.assign block, node }, __index: sc + -- records an error if the stage is enabled + lint_report: (stage, msg, pos) => + root = @root + return if root.lint_stages and not root.lint_stages[stage] + insert root.lint_errors, {msg, pos} + lint_mark_used: (name) => if @lint_unused_names and @lint_unused_names[name] @lint_unused_names[name] = false @@ -160,10 +170,8 @@ class LinterBlock extends Block table.sort tuples, (a,b) -> a[1] < b[1] for {pos, names} in *tuples - insert @root.lint_errors, { - "assigned but unused #{table.concat ["`#{n}`" for n in *names], ", "}" - pos - } + @root\lint_report "unused", + "assigned but unused #{table.concat ["`#{n}`" for n in *names], ", "}", pos render: (...) => @lint_check_unused! @@ -228,21 +236,21 @@ whitelist_for_file = do setmetatable Set(final_list), __index: default_whitelist -lint_code = (code, name="string input", whitelist_globals) -> +lint_code = (code, name="string input", whitelist_globals, stages) -> parse = require "moonscript.parse" tree, err = parse.string code return nil, err unless tree - scope = LinterBlock whitelist_globals + scope = LinterBlock whitelist_globals, stages scope\stms tree scope\lint_check_unused! format_lint scope.lint_errors, code, name -lint_file = (fname) -> +lint_file = (fname, stages) -> f, err = io.open fname return nil, err unless f - lint_code f\read("*a"), fname, whitelist_for_file fname + lint_code f\read("*a"), fname, whitelist_for_file(fname), stages -{ :lint_code, :lint_file } +{ :lint_code, :lint_file, :lint_stages } diff --git a/spec/lint_spec.moon b/spec/lint_spec.moon index ce3609a0..4d84b205 100644 --- a/spec/lint_spec.moon +++ b/spec/lint_spec.moon @@ -169,3 +169,29 @@ describe "linter", -> ======================================= > import insert from require "custom" ]]), lint.lint_code code + + it "limits reporting to the given stages", -> + code = unindent [[ + import insert from table + insert = 5 + do + unused_var = 1 + missing_global 10 + ]] + + result = lint.lint_code code, nil, nil, {"constant_assign"} + assert.same unindent([[ + string input + + line 2: assigning to constant `insert` + ====================================== + > insert = 5 + ]]), result + + result = lint.lint_code code, nil, nil, {"global_access", "unused"} + assert.truthy result\match "accessing global" + assert.truthy result\match "assigned but unused" + assert.is_nil result\match "assigning to constant" + + assert.is_nil (lint.lint_code code, nil, nil, {"import_overwrite"}) + assert.is_nil (lint.lint_code code, nil, nil, {}) From dc6d881f70868c78acd5a805b225ee512af2e0a7 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 25 Jul 2026 15:52:41 -0700 Subject: [PATCH 545/554] add alternate lint output format, fixes #465 TODO: need to have similar thing for parse errors, but that will come after we merge in the new parser --- bin/moonc | 27 ++++++++++++++---- docs/command_line.md | 9 ++++++ moonscript/cmd/lint.lua | 61 ++++++++++++++++++++++++++++++++++------ moonscript/cmd/lint.moon | 44 +++++++++++++++++++++++------ moonscript/util.lua | 18 ++++++++++-- moonscript/util.moon | 19 +++++++++---- spec/lint_spec.moon | 40 +++++++++++++++++++++++--- 7 files changed, 184 insertions(+), 34 deletions(-) diff --git a/bin/moonc b/bin/moonc index 50f2943c..6cff7443 100644 --- a/bin/moonc +++ b/bin/moonc @@ -8,18 +8,25 @@ local parser = argparse() parser:flag("-l --lint", "Perform a lint on the file instead of compiling") -- may be nil when an older moonscript.cmd.lint is loaded from the module path -local all_lint_stages = require("moonscript.cmd.lint").lint_stages +local all_lint_stages = require("moonscript.cmd.lint").LINT_STAGES +local all_lint_formats = require("moonscript.cmd.lint").LINT_FORMATS local lint_stage_opt = parser:option("--lint-stage", "Limit lint to the given stage name (repeatable)"):count("*") local exclude_lint_stage_opt = parser:option("--exclude-lint-stage", "Lint with all stages except the given stage name (repeatable)"):count("*") +local lint_format_opt = parser:option("--lint-format", + "Set the output format of lint results") if all_lint_stages then lint_stage_opt:choices(all_lint_stages) exclude_lint_stage_opt:choices(all_lint_stages) end +if all_lint_formats then + lint_format_opt:choices(all_lint_formats) +end + parser:mutex(lint_stage_opt, exclude_lint_stage_opt) parser:flag("-v --version", "Print version"):action(function() @@ -54,9 +61,10 @@ end local opts = read_stdin and {} or parser:parse() --- the list of lint stages to run, nil runs all of them -local lint_stages +-- options passed to lint_file, stages: nil runs all of them +local lint_opts do + local lint_stages local included, excluded = opts.lint_stage, opts.exclude_lint_stage if included and #included > 0 then lint_stages = included @@ -73,6 +81,11 @@ do end end end + + lint_opts = { + stages = lint_stages, + format = opts.lint_format, + } end function log_msg(...) @@ -188,7 +201,7 @@ if opts.watch then if opts.lint then local lint = require "moonscript.cmd.lint" handle_file = function(fname) - return lint.lint_file(fname, lint_stages) + return lint.lint_file(fname, lint_opts) end else handle_file = compile_and_write @@ -237,10 +250,12 @@ elseif opts.lint then local lint = require "moonscript.cmd.lint" for _, tuple in pairs(files) do local fname = tuple[1] - local res, err = lint.lint_file(fname, lint_stages) + local res, err = lint.lint_file(fname, lint_opts) if res then has_linted_with_error = true - io.stderr:write(res .. "\n\n") + -- compact format lines identify their file, no separator needed + local sep = opts.lint_format == "compact" and "\n" or "\n\n" + io.stderr:write(res .. sep) elseif err then has_linted_with_error = true io.stderr:write(fname .. "\n" .. err.. "\n\n") diff --git a/docs/command_line.md b/docs/command_line.md index 7accdf11..0d69f4da 100644 --- a/docs/command_line.md +++ b/docs/command_line.md @@ -179,6 +179,15 @@ moonc -l --lint-stage global_access --lint-stage unused . moonc -l --exclude-lint-stage import_overwrite . ``` +The `--lint-format` option changes how results are printed. The `compact` +format writes one `file:line:column: message [stage]` line per issue, +suitable for tools and editors that parse compiler style output: + +```bash +$ moonc -l --lint-format compact lint_example.moon +lint_example.moon:7:5: accessing global `my_nmuber` [global_access] +``` + Like when compiling, you can also pass a directory as a command line argument to recursively process all the `.moon` files. diff --git a/moonscript/cmd/lint.lua b/moonscript/cmd/lint.lua index 1f4a2b8c..21aedcf8 100644 --- a/moonscript/cmd/lint.lua +++ b/moonscript/cmd/lint.lua @@ -52,7 +52,7 @@ local default_whitelist = Set({ "true", "false" }) -local lint_stages = { +local LINT_STAGES = { "global_access", "unused", "constant_assign", @@ -70,7 +70,8 @@ do end return insert(root.lint_errors, { msg, - pos + pos, + stage }) end, lint_mark_used = function(self, name) @@ -284,6 +285,37 @@ do end LinterBlock = _class_0 end +local format_lint_compact +format_lint_compact = function(errors, code, header) + if not (next(errors)) then + return nil + end + local pos_to_line_col + pos_to_line_col = require("moonscript.util").pos_to_line_col + local formatted + do + local _accum_0 = { } + local _len_0 = 1 + for _index_0 = 1, #errors do + local _des_0 = errors[_index_0] + local msg, pos, stage + msg, pos, stage = _des_0[1], _des_0[2], _des_0[3] + local location + if pos then + local line, col = pos_to_line_col(code, pos) + location = tostring(header) .. ":" .. tostring(line) .. ":" .. tostring(col) + else + location = header + end + local stage_suffix = stage and " [" .. tostring(stage) .. "]" or "" + local _value_0 = tostring(location) .. ": " .. tostring(msg) .. tostring(stage_suffix) + _accum_0[_len_0] = _value_0 + _len_0 = _len_0 + 1 + end + formatted = _accum_0 + end + return table.concat(formatted, "\n") +end local format_lint format_lint = function(errors, code, header) if not (next(errors)) then @@ -351,8 +383,16 @@ do }) end end +local LINT_FORMATS = { + "default", + "compact" +} +local formatters = { + default = format_lint, + compact = format_lint_compact +} local lint_code -lint_code = function(code, name, whitelist_globals, stages) +lint_code = function(code, name, whitelist_globals, opts) if name == nil then name = "string input" end @@ -361,21 +401,26 @@ lint_code = function(code, name, whitelist_globals, stages) if not (tree) then return nil, err end - local scope = LinterBlock(whitelist_globals, stages) + local scope = LinterBlock(whitelist_globals, opts and opts.stages) scope:stms(tree) scope:lint_check_unused() - return format_lint(scope.lint_errors, code, name) + local formatter = formatters[opts and opts.format or "default"] + if not (formatter) then + error("unknown lint format: " .. tostring(opts.format)) + end + return formatter(scope.lint_errors, code, name) end local lint_file -lint_file = function(fname, stages) +lint_file = function(fname, opts) local f, err = io.open(fname) if not (f) then return nil, err end - return lint_code(f:read("*a"), fname, whitelist_for_file(fname), stages) + return lint_code(f:read("*a"), fname, whitelist_for_file(fname), opts) end return { lint_code = lint_code, lint_file = lint_file, - lint_stages = lint_stages + LINT_STAGES = LINT_STAGES, + LINT_FORMATS = LINT_FORMATS } diff --git a/moonscript/cmd/lint.moon b/moonscript/cmd/lint.moon index fa5d6000..b767e2c4 100644 --- a/moonscript/cmd/lint.moon +++ b/moonscript/cmd/lint.moon @@ -54,7 +54,7 @@ default_whitelist = Set { } -- the named checks that can be enabled or disabled when linting -lint_stages = { +LINT_STAGES = { "global_access" "unused" "constant_assign" @@ -147,7 +147,7 @@ class LinterBlock extends Block lint_report: (stage, msg, pos) => root = @root return if root.lint_stages and not root.lint_stages[stage] - insert root.lint_errors, {msg, pos} + insert root.lint_errors, {msg, pos, stage} lint_mark_used: (name) => if @lint_unused_names and @lint_unused_names[name] @@ -189,6 +189,23 @@ class LinterBlock extends Block .lint_wrap_transform = @lint_wrap_transform @lint_wrap_transform child +-- one `file:line:col: message [stage]` line per error +format_lint_compact = (errors, code, header) -> + return nil unless next errors + + import pos_to_line_col from require "moonscript.util" + formatted = for {msg, pos, stage} in *errors + location = if pos + line, col = pos_to_line_col code, pos + "#{header}:#{line}:#{col}" + else + header + + stage_suffix = stage and " [#{stage}]" or "" + "#{location}: #{msg}#{stage_suffix}" + + table.concat formatted, "\n" + format_lint = (errors, code, header) -> return unless next errors @@ -236,21 +253,32 @@ whitelist_for_file = do setmetatable Set(final_list), __index: default_whitelist -lint_code = (code, name="string input", whitelist_globals, stages) -> +-- the named output formats for lint results +LINT_FORMATS = {"default", "compact"} + +formatters = { + default: format_lint + compact: format_lint_compact +} + +-- opts: {stages: {stage_name}, format: format_name} +lint_code = (code, name="string input", whitelist_globals, opts) -> parse = require "moonscript.parse" tree, err = parse.string code return nil, err unless tree - scope = LinterBlock whitelist_globals, stages + scope = LinterBlock whitelist_globals, opts and opts.stages scope\stms tree scope\lint_check_unused! - format_lint scope.lint_errors, code, name + formatter = formatters[opts and opts.format or "default"] + error "unknown lint format: #{opts.format}" unless formatter + formatter scope.lint_errors, code, name -lint_file = (fname, stages) -> +lint_file = (fname, opts) -> f, err = io.open fname return nil, err unless f - lint_code f\read("*a"), fname, whitelist_for_file(fname), stages + lint_code f\read("*a"), fname, whitelist_for_file(fname), opts -{ :lint_code, :lint_file, :lint_stages } +{ :lint_code, :lint_file, :LINT_STAGES, :LINT_FORMATS } diff --git a/moonscript/util.lua b/moonscript/util.lua index 93bfdde6..d1a8e759 100644 --- a/moonscript/util.lua +++ b/moonscript/util.lua @@ -29,12 +29,23 @@ mtype = function(value) end return base_type end -local pos_to_line -pos_to_line = function(str, pos) +local pos_to_line_col +pos_to_line_col = function(str, pos) local line = 1 - for _ in str:sub(1, pos):gmatch("\n") do + local line_start = 1 + while true do + local nl = str:find("\n", line_start, true) + if not (nl and nl < pos) then + break + end line = line + 1 + line_start = nl + 1 end + return line, pos - line_start + 1 +end +local pos_to_line +pos_to_line = function(str, pos) + local line = pos_to_line_col(str, pos) return line end local trim @@ -202,6 +213,7 @@ end return { moon = moon, mtype = mtype, + pos_to_line_col = pos_to_line_col, pos_to_line = pos_to_line, get_closest_line = get_closest_line, get_line = get_line, diff --git a/moonscript/util.moon b/moonscript/util.moon index 492a72aa..880fe542 100644 --- a/moonscript/util.moon +++ b/moonscript/util.moon @@ -27,11 +27,21 @@ mtype = (value) -> -- the moonscript object class return cls base_type --- convet position in text to line number -pos_to_line = (str, pos) -> +-- convert position in text to line and column numbers +pos_to_line_col = (str, pos) -> line = 1 - for _ in str\sub(1, pos)\gmatch("\n") + line_start = 1 + while true + nl = str\find "\n", line_start, true + break unless nl and nl < pos line += 1 + line_start = nl + 1 + + line, pos - line_start + 1 + +-- convert position in text to line number +pos_to_line = (str, pos) -> + line = pos_to_line_col str, pos line trim = (str) -> @@ -136,7 +146,6 @@ safe_module = (name, tbl) -> } { - :moon, :mtype, :pos_to_line, :get_closest_line, :get_line, :trim, :split, :dump, + :moon, :mtype, :pos_to_line_col, :pos_to_line, :get_closest_line, :get_line, :trim, :split, :dump, :debug_posmap, :getfenv, :setfenv, :get_options, :unpack, :safe_module } - diff --git a/spec/lint_spec.moon b/spec/lint_spec.moon index 4d84b205..070b7922 100644 --- a/spec/lint_spec.moon +++ b/spec/lint_spec.moon @@ -179,7 +179,7 @@ describe "linter", -> missing_global 10 ]] - result = lint.lint_code code, nil, nil, {"constant_assign"} + result = lint.lint_code code, nil, nil, stages: {"constant_assign"} assert.same unindent([[ string input @@ -188,10 +188,42 @@ describe "linter", -> > insert = 5 ]]), result - result = lint.lint_code code, nil, nil, {"global_access", "unused"} + result = lint.lint_code code, nil, nil, stages: {"global_access", "unused"} assert.truthy result\match "accessing global" assert.truthy result\match "assigned but unused" assert.is_nil result\match "assigning to constant" - assert.is_nil (lint.lint_code code, nil, nil, {"import_overwrite"}) - assert.is_nil (lint.lint_code code, nil, nil, {}) + assert.is_nil (lint.lint_code code, nil, nil, stages: {"import_overwrite"}) + assert.is_nil (lint.lint_code code, nil, nil, stages: {}) + + it "formats output with the compact format", -> + code = unindent [[ + import insert from table + insert = 5 + do + unused_var = 1 + f = -> missing_global 10 + f! + ]] + + assert.same unindent([[ + test.moon:2:1: assigning to constant `insert` [constant_assign] + test.moon:4:3: assigned but unused `unused_var` [unused] + test.moon:5:7: accessing global `missing_global` [global_access] + ]]), lint.lint_code code, "test.moon", nil, format: "compact" + + it "combines compact format with stage filter", -> + code = unindent [[ + import insert from table + insert = 5 + missing_global 10 + ]] + + result = lint.lint_code code, "test.moon", nil, { + format: "compact" + stages: {"global_access"} + } + assert.same "test.moon:3:1: accessing global `missing_global` [global_access]", result + + it "compact format returns nothing for clean code", -> + assert.is_nil (lint.lint_code "x = 5\nprint x", "test.moon", nil, format: "compact") From c8eb0c5369232ea1dc82f53dcb8a72f6121cdee3 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 25 Jul 2026 20:18:15 -0700 Subject: [PATCH 546/554] hoist "local x" to top of class body, put hoisted locals after parent reference to avoid overwrite. Fixes #459 --- moonscript/transform/class.lua | 15 ++++++- moonscript/transform/class.moon | 18 ++++++++- spec/inputs/class.moon | 15 +++++++ spec/outputs/class.lua | 71 +++++++++++++++++++++++++++++++++ 4 files changed, 115 insertions(+), 4 deletions(-) diff --git a/moonscript/transform/class.lua b/moonscript/transform/class.lua index 74f93c59..6c71a2f2 100644 --- a/moonscript/transform/class.lua +++ b/moonscript/transform/class.lua @@ -124,11 +124,17 @@ return function(self, node, ret, parent_assign) end local statements = { } local properties = { } + local hoisted_locals = { } for _index_0 = 1, #body do local item = body[_index_0] local _exp_0 = item[1] if "stm" == _exp_0 then - insert(statements, item[2]) + local stm = item[2] + if ntype(stm) == "declare_with_shadows" then + insert(hoisted_locals, stm) + else + insert(statements, stm) + end elseif "props" == _exp_0 then for _index_1 = 2, #item do local tuple = item[_index_1] @@ -403,11 +409,16 @@ return function(self, node, ret, parent_assign) cls_name } }, + parent_val and build.assign_one(parent_cls_name, parent_val) or NOOP, + build.group((function() + if #hoisted_locals > 0 then + return hoisted_locals + end + end)()), { "declare_glob", "*" }, - parent_val and build.assign_one(parent_cls_name, parent_val) or NOOP, build.assign_one(base_name, { "table", properties diff --git a/moonscript/transform/class.moon b/moonscript/transform/class.moon index 7451375b..e0278431 100644 --- a/moonscript/transform/class.moon +++ b/moonscript/transform/class.moon @@ -93,10 +93,19 @@ super_scope = (value, t, key) -> -- split apart properties and statements statements = {} properties = {} + + -- local declarations are hoisted to the top of the class scope so methods + -- can close over the names + hoisted_locals = {} + for item in *body switch item[1] when "stm" - insert statements, item[2] + stm = item[2] + if ntype(stm) == "declare_with_shadows" + insert hoisted_locals, stm + else + insert statements, stm when "props" for tuple in *item[2,] if ntype(tuple[1]) == "self" @@ -233,10 +242,15 @@ super_scope = (value, t, key) -> @put_name name if name {"declare", { cls_name }} - {"declare_glob", "*"} + -- the parent expression is evaluated before the local shadows are + -- installed so it can reference a name a class body local overrides parent_val and .assign_one(parent_cls_name, parent_val) or NOOP + .group if #hoisted_locals > 0 then hoisted_locals + + {"declare_glob", "*"} + .assign_one base_name, {"table", properties} .assign_one base_name\chain"__index", base_name diff --git a/spec/inputs/class.moon b/spec/inputs/class.moon index 9a980557..56b0ae1c 100644 --- a/spec/inputs/class.moon +++ b/spec/inputs/class.moon @@ -194,6 +194,21 @@ class Whack extends Thing --- +class LocalHoist + local one_thing, another_thing + + one_thing = "hello" + + get_thing: => one_thing + set_thing: (v) => another_thing = v + +class LocalHoistExtends extends LocalHoist + local LocalHoist + + get_class: => LocalHoist + +--- + class Wowha extends Thing @butt: -> super! diff --git a/spec/outputs/class.lua b/spec/outputs/class.lua index 018760a0..359a6f1c 100644 --- a/spec/outputs/class.lua +++ b/spec/outputs/class.lua @@ -850,6 +850,77 @@ do end Whack = _class_0 end +do + local _class_0 + local one_thing, another_thing + local _base_0 = { + get_thing = function(self) + return one_thing + end, + set_thing = function(self, v) + another_thing = v + end + } + _base_0.__index = _base_0 + _class_0 = setmetatable({ + __init = function() end, + __base = _base_0, + __name = "LocalHoist" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + one_thing = "hello" + LocalHoist = _class_0 +end +do + local _class_0 + local _parent_0 = LocalHoist + local LocalHoist + local _base_0 = { + get_class = function(self) + return LocalHoist + end + } + _base_0.__index = _base_0 + setmetatable(_base_0, _parent_0.__base) + _class_0 = setmetatable({ + __init = function(self, ...) + return _class_0.__parent.__init(self, ...) + end, + __base = _base_0, + __name = "LocalHoistExtends", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil then + local parent = rawget(cls, "__parent") + if parent then + return parent[name] + end + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + LocalHoistExtends = _class_0 +end do local _class_0 local _parent_0 = Thing From 917dd5f49ce619a3e206b5438978de57775776a2 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sat, 25 Jul 2026 21:13:35 -0700 Subject: [PATCH 547/554] use autogen _scrap_N name for expression lines coerced into statements intead of _, fixes #309 --- moonscript/compile.lua | 6 +++- moonscript/compile.moon | 7 +++- moonscript/transform/destructure.lua | 2 +- moonscript/transform/destructure.moon | 2 +- spec/outputs/assign.lua | 4 +-- spec/outputs/class.lua | 26 +++++++------- spec/outputs/comprehension.lua | 16 ++++----- spec/outputs/cond.lua | 30 ++++++++-------- spec/outputs/destructure.lua | 9 ++--- spec/outputs/do.lua | 4 +-- spec/outputs/funcs.lua | 30 ++++++++-------- spec/outputs/lists.lua | 6 ++-- spec/outputs/literals.lua | 50 +++++++++++++-------------- spec/outputs/local.lua | 2 +- spec/outputs/loops.lua | 14 ++++---- spec/outputs/return.lua | 12 +++---- spec/outputs/string.lua | 2 +- spec/outputs/switch.lua | 10 +++--- spec/outputs/syntax.lua | 42 +++++++++++----------- spec/outputs/tables.lua | 2 +- spec/outputs/using.lua | 8 ++--- spec/outputs/whitespace.lua | 22 ++++++------ spec/outputs/with.lua | 6 ++-- 23 files changed, 161 insertions(+), 151 deletions(-) diff --git a/moonscript/compile.lua b/moonscript/compile.lua index 0dace036..d8d3a127 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -423,6 +423,10 @@ do }) return name end, + discard_name = function(self) + self._discard_name = self._discard_name or NameProxy("scrap") + return self._discard_name + end, add = function(self, item, pos) do local _with_0 = self._lines @@ -541,7 +545,7 @@ do result = self:stm({ "assign", { - "_" + self:discard_name() }, { node diff --git a/moonscript/compile.moon b/moonscript/compile.moon index 2ea34c60..9e5ab210 100644 --- a/moonscript/compile.moon +++ b/moonscript/compile.moon @@ -297,6 +297,11 @@ class Block @stm {"assign", {name}, {value}} name + -- expressions that need to be coerced into statements are assigned to this name + discard_name: => + @_discard_name or= NameProxy "scrap" + @_discard_name + -- add something to the line buffer add: (item, pos) => with @_lines @@ -390,7 +395,7 @@ class Block @value node else -- coerce value into statement - @stm {"assign", {"_"}, {node}} + @stm {"assign", {@discard_name!}, {node}} if result if type(node) == "table" and type(result) == "table" and node[-1] diff --git a/moonscript/transform/destructure.lua b/moonscript/transform/destructure.lua index acdaa346..5f1e35a0 100644 --- a/moonscript/transform/destructure.lua +++ b/moonscript/transform/destructure.lua @@ -319,7 +319,7 @@ split_assign = function(scope, assign) local name_slice if total_names < start then name_slice = { - "_" + scope:discard_name() } else do diff --git a/moonscript/transform/destructure.moon b/moonscript/transform/destructure.moon index 3ac34754..89af26f0 100644 --- a/moonscript/transform/destructure.moon +++ b/moonscript/transform/destructure.moon @@ -195,7 +195,7 @@ split_assign = (scope, assign) -> insert g, build_assign scope, literal, proxy elseif total_names >= start or total_values >= start name_slice = if total_names < start - {"_"} + {scope\discard_name!} else for i=start,total_names do names[i] diff --git a/spec/outputs/assign.lua b/spec/outputs/assign.lua index 1bcc3cad..4a9ed73f 100644 --- a/spec/outputs/assign.lua +++ b/spec/outputs/assign.lua @@ -1,5 +1,5 @@ -local _ -_ = function() +local _scrap_0 +_scrap_0 = function() local joop = 2302 return function(hi) local d = 100 diff --git a/spec/outputs/class.lua b/spec/outputs/class.lua index 359a6f1c..4ea9f31b 100644 --- a/spec/outputs/class.lua +++ b/spec/outputs/class.lua @@ -338,14 +338,14 @@ do hi = function(self) _class_0.__parent.__base.hi(self, 1, 2, 3, 4)(1, 2, 3, 4) _class_0.__parent.something(1, 2, 3, 4) - local _ = _class_0.__parent.something(1, 2, 3, 4).world + local _scrap_0 = _class_0.__parent.something(1, 2, 3, 4).world _class_0.__parent.yeah(self, "world").okay(hi, hi, hi) - _ = something.super - _ = _class_0.__parent.super.super.super + _scrap_0 = something.super + _scrap_0 = _class_0.__parent.super.super.super do local _base_1 = _class_0.__parent local _fn_0 = _base_1.hello - _ = function(...) + _scrap_0 = function(...) return _fn_0(self, ...) end end @@ -412,7 +412,7 @@ self.__class(something) local self = self + self / self self = 343 self.hello(2, 3, 4) -local _ = hello[self].world +local _scrap_0 = hello[self].world local Whacko do local _class_0 @@ -433,7 +433,7 @@ do }) _base_0.__class = _class_0 local self = _class_0 - _ = self.hello + local _scrap_1 = self.hello if something then print("hello world") end @@ -466,7 +466,7 @@ yyy = function() }) _base_0.__class = _class_0 local self = _class_0 - _ = nil + local _scrap_1 = nil Cool = _class_0 return _class_0 end @@ -489,7 +489,7 @@ do }) _base_0.__class = _class_0 local self = _class_0 - _ = nil + local _scrap_1 = nil a.b.c.D = _class_0 end do @@ -510,7 +510,7 @@ do }) _base_0.__class = _class_0 local self = _class_0 - _ = nil + local _scrap_1 = nil a.b["hello"] = _class_0 end do @@ -546,7 +546,7 @@ do }) _base_0.__class = _class_0 local self = _class_0 - _ = nil + local _scrap_1 = nil if _parent_0.__inherited then _parent_0.__inherited(_parent_0, _class_0) end @@ -714,7 +714,7 @@ do }) _base_0.__class = _class_0 local self = _class_0 - _ = nil + local _scrap_1 = nil Something = _class_0 end do @@ -956,7 +956,7 @@ do local self = _class_0 self.butt = function() _class_0.__parent.butt(self) - _ = _class_0.__parent.hello + local _scrap_1 = _class_0.__parent.hello _class_0.__parent.hello(self) local _base_1 = _class_0.__parent local _fn_0 = _base_1.hello @@ -967,7 +967,7 @@ do self.zone = cool({ function() _class_0.__parent.zone(self) - _ = _class_0.__parent.hello + local _scrap_1 = _class_0.__parent.hello _class_0.__parent.hello(self) local _base_1 = _class_0.__parent local _fn_0 = _base_1.hello diff --git a/spec/outputs/comprehension.lua b/spec/outputs/comprehension.lua index 15a93890..14e1ca7c 100644 --- a/spec/outputs/comprehension.lua +++ b/spec/outputs/comprehension.lua @@ -28,14 +28,14 @@ do end copy = _tbl_0 end -local _ +local _scrap_0 do local _tbl_0 = { } for x in yes do local _key_0, _val_0 = unpack(x) _tbl_0[_key_0] = _val_0 end - _ = _tbl_0 + _scrap_0 = _tbl_0 end do local _tbl_0 = { } @@ -45,7 +45,7 @@ do local _key_0, _val_0 = unpack(x) _tbl_0[_key_0] = _val_0 end - _ = _tbl_0 + _scrap_0 = _tbl_0 end do local _tbl_0 = { } @@ -53,7 +53,7 @@ do local _key_0, _val_0 = xxxx _tbl_0[_key_0] = _val_0 end - _ = _tbl_0 + _scrap_0 = _tbl_0 end do local _tbl_0 = { } @@ -80,7 +80,7 @@ do end)()) _tbl_0[_key_0] = _val_0 end - _ = _tbl_0 + _scrap_0 = _tbl_0 end local n1 do @@ -166,7 +166,7 @@ do for i = 1, 10 do _tbl_0["hello"] = "world" end - _ = _tbl_0 + _scrap_0 = _tbl_0 end local j do @@ -250,11 +250,11 @@ end local _max_0 = 3 + 4 for _index_0 = 1 + 2, _max_0 < 0 and #items + _max_0 or _max_0 do local item = items[_index_0] - _ = item + local _scrap_1 = item end local _max_1 = 2 - thing[4] for _index_0 = hello() * 4, _max_1 < 0 and #items + _max_1 or _max_1 do local item = items[_index_0] - _ = item + local _scrap_1 = item end return nil \ No newline at end of file diff --git a/spec/outputs/cond.lua b/spec/outputs/cond.lua index 35e7ac56..f3ca1a6b 100644 --- a/spec/outputs/cond.lua +++ b/spec/outputs/cond.lua @@ -1,25 +1,25 @@ local you_cool = false if cool then if you_cool then - local _ = one + local _scrap_0 = one else if eatdic then - local _ = yeah + local _scrap_0 = yeah else - local _ = two - _ = three + local _scrap_0 = two + _scrap_0 = three end end else - local _ = no + local _scrap_0 = no end if cool then - local _ = no + local _scrap_0 = no end if cool then - local _ = no + local _scrap_0 = no else - local _ = yes + local _scrap_0 = yes end if cool then wow(cool) @@ -29,12 +29,12 @@ end if working then if cool then if cool then - local _ = okay + local _scrap_0 = okay else - local _ = what + local _scrap_0 = what end else - local _ = nah + local _scrap_0 = nah end end if yeah then @@ -112,19 +112,19 @@ hello = 5 + (function() end)() local z = false if false then - local _ = one + local _scrap_0 = one else do local x = true if x then - local _ = two + local _scrap_0 = two else do z = true if z then - local _ = three + local _scrap_0 = three else - local _ = four + local _scrap_0 = four end end end diff --git a/spec/outputs/destructure.lua b/spec/outputs/destructure.lua index 2f44e329..0342ac62 100644 --- a/spec/outputs/destructure.lua +++ b/spec/outputs/destructure.lua @@ -27,7 +27,7 @@ do a, b, c, d = _obj_0.a, _obj_0.b, _obj_0.c, _obj_0.d end a = one[1] - local _ = two + local _scrap_0 = two b = one[1] c = nil d = one[1] @@ -154,14 +154,15 @@ do a, b, c = _obj_0[1], _obj_0[2], _obj_0[3] end end -local _ -_ = function(z) +local _scrap_0 +_scrap_0 = function(z) local a, b, c a, b, c = z[1], z[2], z[3] end do local z = "oo" - _ = function(k) + local _scrap_1 + _scrap_1 = function(k) local a, b, c a, b, c = z[1], z[2], z[3] end diff --git a/spec/outputs/do.lua b/spec/outputs/do.lua index bfd7090b..e07b43c9 100644 --- a/spec/outputs/do.lua +++ b/spec/outputs/do.lua @@ -14,8 +14,8 @@ do return "hello: " .. things end end -local _ -_ = function() +local _scrap_0 +_scrap_0 = function() if something then do return "yeah" diff --git a/spec/outputs/funcs.lua b/spec/outputs/funcs.lua index f5e2cf3c..5ce19ca3 100644 --- a/spec/outputs/funcs.lua +++ b/spec/outputs/funcs.lua @@ -2,9 +2,9 @@ local x x = function() return print(what) end -local _ -_ = function() end -_ = function() +local _scrap_0 +_scrap_0 = function() end +_scrap_0 = function() return function() return function() end end @@ -31,19 +31,19 @@ eat(function() end, world); x = function(...) end hello() hello.world() -_ = hello().something -_ = what()["ofefe"] +_scrap_0 = hello().something +_scrap_0 = what()["ofefe"] what()(the()(heck())) -_ = function(a, b, c, d, e) end -_ = function(a, a, a, a, a) +_scrap_0 = function(a, b, c, d, e) end +_scrap_0 = function(a, a, a, a, a) return print(a) end -_ = function(x) +_scrap_0 = function(x) if x == nil then x = 23023 end end -_ = function(x) +_scrap_0 = function(x) if x == nil then x = function(y) if y == nil then @@ -52,7 +52,7 @@ _ = function(x) end end end -_ = function(x) +_scrap_0 = function(x) if x == nil then if something then x = yeah @@ -76,16 +76,16 @@ something = function(hello, world) end return print(hello) end -_ = function(self, x, y) end -_ = function(self, x, y) +_scrap_0 = function(self, x, y) end +_scrap_0 = function(self, x, y) self.x, self.y = x, y end -_ = function(self, x) +_scrap_0 = function(self, x) if x == nil then x = 1 end end -_ = function(self, x, y, z) +_scrap_0 = function(self, x, y, z) if x == nil then x = 1 end @@ -108,7 +108,7 @@ k(function() return end end) -_ = function() +_scrap_0 = function() if something then return real_name end diff --git a/spec/outputs/lists.lua b/spec/outputs/lists.lua index abb167eb..a3e701a0 100644 --- a/spec/outputs/lists.lua +++ b/spec/outputs/lists.lua @@ -23,7 +23,7 @@ local items = { } for z in ipairs(items) do if z > 4 then - local _ = z + local _scrap_0 = z end end local rad @@ -50,7 +50,7 @@ end for z in items do for j in list do if z > 4 then - local _ = z + local _scrap_0 = z end end end @@ -129,7 +129,7 @@ for x in items do print("hello", x) end for x in x do - local _ = x + local _scrap_0 = x end local x do diff --git a/spec/outputs/literals.lua b/spec/outputs/literals.lua index d8fc7e2b..b0d8ccbc 100644 --- a/spec/outputs/literals.lua +++ b/spec/outputs/literals.lua @@ -1,26 +1,26 @@ -local _ = 121 -_ = 121.2323 -_ = 121.2323e-1 -_ = 121.2323e13434 -_ = 2323E34 -_ = 0x12323 -_ = 0xfF2323 -_ = 0xabcdef -_ = 0xABCDEF -_ = .2323 -_ = .2323e-1 -_ = .2323e13434 -_ = 1LL -_ = 1ULL -_ = 9332LL -_ = 9332 -_ = 0x2aLL -_ = 0x2aULL -_ = [[ hello world ]] -_ = [=[ hello world ]=] -_ = [====[ hello world ]====] -_ = "another world" -_ = 'what world' -_ = "\nhello world\n" -_ = 'yeah\nwhat is going on\nhere is something cool' +local _scrap_0 = 121 +_scrap_0 = 121.2323 +_scrap_0 = 121.2323e-1 +_scrap_0 = 121.2323e13434 +_scrap_0 = 2323E34 +_scrap_0 = 0x12323 +_scrap_0 = 0xfF2323 +_scrap_0 = 0xabcdef +_scrap_0 = 0xABCDEF +_scrap_0 = .2323 +_scrap_0 = .2323e-1 +_scrap_0 = .2323e13434 +_scrap_0 = 1LL +_scrap_0 = 1ULL +_scrap_0 = 9332LL +_scrap_0 = 9332 +_scrap_0 = 0x2aLL +_scrap_0 = 0x2aULL +_scrap_0 = [[ hello world ]] +_scrap_0 = [=[ hello world ]=] +_scrap_0 = [====[ hello world ]====] +_scrap_0 = "another world" +_scrap_0 = 'what world' +_scrap_0 = "\nhello world\n" +_scrap_0 = 'yeah\nwhat is going on\nhere is something cool' return nil \ No newline at end of file diff --git a/spec/outputs/local.lua b/spec/outputs/local.lua index 3ee8623e..a186aa57 100644 --- a/spec/outputs/local.lua +++ b/spec/outputs/local.lua @@ -141,7 +141,7 @@ do local _list_0 = { } for _index_0 = 1, #_list_0 do local a = _list_0[_index_0] - local _ = a + local _scrap_0 = a end end local g = 2323 \ No newline at end of file diff --git a/spec/outputs/loops.lua b/spec/outputs/loops.lua index 89af865f..ca522638 100644 --- a/spec/outputs/loops.lua +++ b/spec/outputs/loops.lua @@ -38,7 +38,7 @@ end local x x = function() for x in y do - local _ = y + local _scrap_0 = y end end local hello = { @@ -63,7 +63,7 @@ end x = function() for _index_0 = 1, #hello do local x = hello[_index_0] - local _ = y + local _scrap_0 = y end end local t @@ -89,13 +89,13 @@ do end y = _accum_0 end -local _ -_ = function() +local _scrap_0 +_scrap_0 = function() for k = 10, 40 do - _ = "okay" + local _scrap_1 = "okay" end end -_ = function() +_scrap_0 = function() return (function() local _accum_0 = { } local _len_0 = 1 @@ -115,7 +115,7 @@ while 5 + 5 do end while also do i(work(too)) - _ = "okay" + local _scrap_1 = "okay" end local i = 0 do diff --git a/spec/outputs/return.lua b/spec/outputs/return.lua index 4eeaca20..5ce2e7e6 100644 --- a/spec/outputs/return.lua +++ b/spec/outputs/return.lua @@ -1,12 +1,12 @@ -local _ -_ = function() +local _scrap_0 +_scrap_0 = function() local _list_0 = things for _index_0 = 1, #_list_0 do local x = _list_0[_index_0] - _ = x + local _scrap_1 = x end end -_ = function() +_scrap_0 = function() local _accum_0 = { } local _len_0 = 1 local _list_0 = things @@ -44,7 +44,7 @@ do end return _tbl_0 end -_ = function() +_scrap_0 = function() if a then if a then return a @@ -86,7 +86,7 @@ do end end end -_ = function() +_scrap_0 = function() local _base_0 = a local _fn_0 = _base_0.b return function(...) diff --git a/spec/outputs/string.lua b/spec/outputs/string.lua index 98e33b8a..0eb1ff31 100644 --- a/spec/outputs/string.lua +++ b/spec/outputs/string.lua @@ -26,7 +26,7 @@ local f = [[hello #{world} world]] a = 'hello #{hello} hello' b = '#{hello} hello' c = 'hello #{hello}' -local _ = "hello"; +local _scrap_0 = "hello"; ("hello"):format(1); ("hello"):format(1, 2, 3); ("hello"):format(1, 2, 3)(1, 2, 3); diff --git a/spec/outputs/switch.lua b/spec/outputs/switch.lua index 764c530f..aa9389db 100644 --- a/spec/outputs/switch.lua +++ b/spec/outputs/switch.lua @@ -12,7 +12,7 @@ local _exp_2 = value if "cool" == _exp_2 then print("hello world") elseif "yeah" == _exp_2 then - local _ = [[FFFF]] + [[MMMM]] + local _scrap_0 = [[FFFF]] + [[MMMM]] elseif (2323 + 32434) == _exp_2 then print("okay") else @@ -37,9 +37,9 @@ do local _with_0 = something local _exp_5 = _with_0:value() if _with_0.okay == _exp_5 then - local _ = "world" + local _scrap_0 = "world" else - local _ = "yesh" + local _scrap_0 = "yesh" end end fix(this) @@ -53,13 +53,13 @@ call_func((function() end)()) local _exp_5 = hi if (hello or world) == _exp_5 then - local _ = greene + local _scrap_0 = greene end local _exp_6 = hi if "one" == _exp_6 or "two" == _exp_6 then print("cool") elseif "dad" == _exp_6 then - local _ = no + local _scrap_0 = no end local _exp_7 = hi if (3 + 1) == _exp_7 or hello() == _exp_7 or (function() diff --git a/spec/outputs/syntax.lua b/spec/outputs/syntax.lua index 9a34be5c..1c43742c 100644 --- a/spec/outputs/syntax.lua +++ b/spec/outputs/syntax.lua @@ -18,26 +18,26 @@ fun(a)(b, bad(hello)) hello(world(what(are(you(doing(here)))))) what(the)[3243](world, yeck(heck)) hairy[hands][are](gross)(okay(okay[world])) -local _ = (get[something] + 5)[years] +local _scrap_0 = (get[something] + 5)[years] local i, x = 200, 300 local yeah = (1 + 5) * 3 yeah = ((1 + 5) * 3) / 2 yeah = ((1 + 5) * 3) / 2 + i % 100 local whoa = (1 + 2) * (3 + 4) * (4 + 5) -_ = function() +_scrap_0 = function() if something then return 1, 2, 4 end return print("hello") end -_ = function() +_scrap_0 = function() if hello then return "heloo", "world" else return no, way end end -_ = function() +_scrap_0 = function() return 1, 2, 34 end return 5 + function() @@ -47,21 +47,21 @@ return 5 + (function() return 4 end) + 2 print(5 + function() - _ = 34 + local _scrap_1 = 34 return good(nads) end) something('else', "ya") something('else') something("else") -_ = something([[hey]]) * 2 -_ = something([======[hey]======]) * 2 -_ = something('else'), 2 -_ = something("else"), 2 -_ = something([[else]]), 2 +_scrap_0 = something([[hey]]) * 2 +_scrap_0 = something([======[hey]======]) * 2 +_scrap_0 = something('else'), 2 +_scrap_0 = something("else"), 2 +_scrap_0 = something([[else]]), 2 something('else', 2) something("else", 2) something([[else]], 2) -_ = here(we)("go")[12123] +_scrap_0 = here(we)("go")[12123] local something = { test = 12323, what = function() @@ -120,12 +120,12 @@ for i = 1, 10 do end print("nutjob") if hello then - _ = 343 + local _scrap_1 = 343 end if cool then print("what") else - _ = whack + local _scrap_1 = whack end local arg = { ... @@ -148,7 +148,7 @@ x = #{ 2 } } -_ = hello, world +_scrap_0 = hello, world something:hello(what)(a, b) something:hello(what) something.hello:world(a, b) @@ -178,7 +178,7 @@ x = 0 local _list_0 = values for _index_0 = 1, #_list_0 do local v = _list_0[_index_0] - _ = ((function() + local _scrap_1 = ((function() if ntype(v) == "fndef" then x = x + 1 end @@ -194,9 +194,9 @@ hello = { div({ class = "cool" }) -_ = 5 + what(wack) +_scrap_0 = 5 + what(wack) what(whack + 5) -_ = 5 - what(wack) +_scrap_0 = 5 - what(wack) what(whack - 5) x = hello - world - something; (function(something) @@ -210,16 +210,16 @@ x = hello - world - something; return print(something) end)() if something then - _ = 03589 + local _scrap_1 = 03589 else - _ = 3434 + local _scrap_1 = 3434 end if something then - _ = yeah + local _scrap_1 = yeah elseif "ymmm" then print("cool") else - _ = okay + local _scrap_1 = okay end x = notsomething y = ifsomething diff --git a/spec/outputs/tables.lua b/spec/outputs/tables.lua index b6a4f587..3d568b47 100644 --- a/spec/outputs/tables.lua +++ b/spec/outputs/tables.lua @@ -168,7 +168,7 @@ thing({ what = "great", no = "more" }) -local _ = { +local _scrap_0 = { okay = 123 } local k = { diff --git a/spec/outputs/using.lua b/spec/outputs/using.lua index 6111d284..c99d4bb9 100644 --- a/spec/outputs/using.lua +++ b/spec/outputs/using.lua @@ -1,14 +1,14 @@ local hello = "hello" local world = "world" -local _ -_ = function() +local _scrap_0 +_scrap_0 = function() local hello = 3223 end -_ = function(a) +_scrap_0 = function(a) local hello = 3223 a = 323 end -_ = function(a, b, c) +_scrap_0 = function(a, b, c) a, b, c = 1, 2, 3 local world = 12321 end diff --git a/spec/outputs/whitespace.lua b/spec/outputs/whitespace.lua index c112a055..27e33347 100644 --- a/spec/outputs/whitespace.lua +++ b/spec/outputs/whitespace.lua @@ -1,30 +1,30 @@ -local _ = { +local _scrap_0 = { 1, 2 } -_ = { +_scrap_0 = { 1, 2 } -_ = { +_scrap_0 = { 1, 2 } -_ = { +_scrap_0 = { 1, 2 } -_ = { +_scrap_0 = { 1, 2 } -_ = { +_scrap_0 = { something(1, 2, 4, 5, 6), 3, 4, 5 } -_ = { +_scrap_0 = { a(1, 2, 3), 4, 5, @@ -33,7 +33,7 @@ _ = { 2, 3 } -_ = { +_scrap_0 = { b(1, 2, 3, 4, 5, 6), 1, 2, @@ -42,19 +42,19 @@ _ = { 2, 3 } -_ = { +_scrap_0 = { 1, 2, 3 } -_ = { +_scrap_0 = { c(1, 2, 3) } hello(1, 2, 3, 4, 1, 2, 3, 4, 4, 5) x(1, 2, 3, 4, 5, 6) hello(1, 2, 3, world(4, 5, 6, 5, 6, 7, 8)) hello(1, 2, 3, world(4, 5, 6, 5, 6, 7, 8), 9, 9) -_ = { +_scrap_0 = { hello(1, 2), 3, 4, diff --git a/spec/outputs/with.lua b/spec/outputs/with.lua index 7abebde8..758e2d54 100644 --- a/spec/outputs/with.lua +++ b/spec/outputs/with.lua @@ -53,7 +53,7 @@ end do do local _with_0 = foo - local _ = _with_0:prop("something").hello + local _scrap_0 = _with_0:prop("something").hello _with_0.prop:send(one) _with_0.prop:send(one) end @@ -154,8 +154,8 @@ do end end do - local _ - _ = function() + local _scrap_0 + _scrap_0 = function() do local _with_0 = hi return _with_0.a, _with_0.b From 70501719549536f843e69e0962dabe4c8c7f8b96 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 26 Jul 2026 09:02:45 -0700 Subject: [PATCH 548/554] update changelog for 0.7.0 --- CHANGELOG.md | 351 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 351 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e8a9f137..05087ed2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,354 @@ +# MoonScript v0.7.0 (2026-07-26) + +This update includes a bunch of syntax bug fixes and cleanups, with a few new +features and an enhanced linter. This will be the last release using LPeg, +future versions will use [the new +parser](https://github.com/leafo/moonscript-parser). + +## Destructuring updates + +### Function arguments can be destructured + +A function argument can now be written as a table literal to destructure the +value passed in. The destructuring patterns are the same ones supported by +assignment, including nested patterns, numeric keys, and `@field` targets: + +```moonscript +dist = ({x: x1, y: y1}, {x: x2, y: y2}) -> + math.sqrt (x2 - x1)^2 + (y2 - y1)^2 + +class Point + new: ({x: @x, y: @y}) => + +render = (name, {:width, :height}, scale=1, ...) -> + print name, width, height, scale, ... +``` + +The argument becomes an internal name and the fields are unpacked at the top of +the function body: + +```lua +render = function(name, _arg_0, scale, ...) + local width, height + width, height = _arg_0.width, _arg_0.height + if scale == nil then + scale = 1 + end + return print(name, width, height, scale, ...) +end +``` + +Destructured arguments always declare fresh locals, so a name in the pattern +shadows an enclosing local of the same name instead of assigning to it. + +Argument initialization now happens in the order the arguments are written, so a +default value can reference a name that an earlier argument destructured: + +```moonscript +scaled = ({:base}, amount = base * 2) -> base + amount +``` + +Because the destructured names are bound at the top of the body, a name in a +pattern can not collide with another argument. `({:a}, a) ->` and `({:self}) =>` +are now compile errors. + +### Destructuring in multiple assignment + +Destructuring can now be used mixed in with other names in multiple assignment (#367, #304): + +```moonscript +num, {:message} = two_values! +head, {:content}, tail = mix! +{value: built}, {:status} = builder\build! +``` + +Previously the assignment was split into separate statements, which broke +destructuring output. + +### Better validation of destructuring targets + +The names extracted by a destructuring pattern are now checked with the same +rule the parser uses for assignment targets. `@@class_field`, index expressions, +and slices are now allowed: + +```moonscript +{x: obj.a, y: obj["b"], z: @prop, w: @@cls_prop} = t +``` + +Destructuring into something that can never be assigned to is now a compile +error instead of generating broken code: + +* `{foo!} = thing` reports `Can't destructure into chain ending in call` +* `{...} = thing` reports `Can't destructure into '...'` + +## Linter updates + +### Lint stages + +The linter's checks are now organized into named stages: `global_access`, +`unused`, `constant_assign`, and `import_overwrite`. Every stage runs by +default. `moonc --lint-stage` limits reporting to the named stage, and +`--exclude-lint-stage` reports everything but the named stage. Both options can +be repeated, and they can not be combined. + +```bash +moonc -l --lint-stage global_access --lint-stage unused . +moonc -l --exclude-lint-stage import_overwrite . +``` + +### New checks + +`import_overwrite` reports an `import` that clobbers a name that is already +bound in scope: + +```moonscript +insert = "hello" +f = -> + import insert from table -- import overwrites existing binding `insert` +``` + +`constant_assign` reports writing to a name that is tagged as constant. In this +version, only the names created by `import` are tagged as constant. For this +release, constant names are only checked in the linter. In the future we will +make constant violation a compiler error. + +```moonscript +import insert from table +insert = 5 -- assigning to constant `insert` +``` + +### Compact lint output + +`moonc --lint-format compact` writes one line per issue in the familiar +`file:line:column: message` shape, with the stage name appended, for editors +and tools that parse compiler output (#465): + +```bash +$ moonc -l --lint-format compact lint_example.moon +lint_example.moon:7:5: accessing global `my_nmuber` [global_access] +``` + +## Standard library updates + +### New class introspection functions + +The `moon` module has four new functions, documented in the [standard +library reference](http://moonscript.org/reference/standard_lib.html): + +* `is_class(value)` tests if a value is a MoonScript class table +* `is_instance(value)` tests if a value is an instance of a MoonScript class +* `is_instance_of(value, cls)` tests if a value is an instance of `cls` or any of + its parents. It throws an error if `value` is not an instance +* `is_subclass_of(cls, parent)` tests if `cls` inherits from `parent`. A class is + not a subclass of itself. It throws an error if `cls` is not a class + +Unlike the old `is_object`, these can tell classes, instances, and `__base` +tables apart. + +`is_object` is now deprecated. It returns truthy for instances, classes, and +`__base` tables, so it can not be used to distinguish them. + +### BREAKING: `moon.type` no longer returns the class object for a class + +`moon.type` now returns the string `"class"` when given a class, and it only +returns the class object for actual instances. Previously a class returned +itself, and a `__base` table returned the class it belonged to, which made it +impossible to tell an instance from the class it came from. + +```moonscript +class MyClass + +type MyClass! -- MyClass (unchanged) +type MyClass -- "class" (was MyClass) +type MyClass.__base -- "table" (was MyClass) +``` + +### BREAKING: changes to `moonscript.util` + +These are internal helpers that were never documented, but they were reachable: + +* `util.moon.type` is now `util.mtype`, to avoid the confusion with the `type` + function in the `moon` module +* `util.moon.is_object` removed, replaced by `util.moon.is_class` and + `util.moon.is_instance` +* `util.moon.is_a` removed, replaced by `is_instance_of` in the `moon` module + +## Code Generation + +### Interpolated strings and nested expressions are parenthesized correctly + +The compiler now knows Lua's operator precedence when writing out an +expression, and it adds parentheses when a nested expression would otherwise be +regrouped by the surrounding operators. String interpolation is the most common +way to get a nested expression, and it was silently generating the wrong math +(#320): + +```moonscript +x = 10 / "#{b}.5" +``` + +**Before:** + +```lua +local x = 10 / tostring(b) .. ".5" +``` + +**After:** + +```lua +local x = 10 / (tostring(b) .. ".5") +``` + +Because `..` is right associative in Lua, an interpolated string on the left +hand side of a `..` is grouped as well. This is observable through the +`__concat` metamethod: + +```moonscript +prefix = "id: #{id}, " .. rest +``` + +**Before:** + +```lua +local prefix = "id: " .. tostring(id) .. ", " .. rest +``` + +**After:** + +```lua +local prefix = ("id: " .. tostring(id) .. ", ") .. rest +``` + +### Prefix operators are grouped in update assignments and switches + +The check for whether a value needs to be wrapped in parentheses did not +account for the prefix operators `#`, `-`, `not`, and `~`, which parse greedily. +An update assignment or a `switch` case with one of them on the left would +compile to the wrong grouping (#457): + +```moonscript +count -= #datum + 1 +total *= -x + 1 +flag and= not a or b +``` + +**Before:** + +```lua +local count = count - #datum + 1 +local total = total * -x + 1 +local flag = flag and not a or b +``` + +**After:** + +```lua +local count = count - (#datum + 1) +local total = total * (-x + 1) +local flag = flag and (not a or b) +``` + +### Expression lines no longer use `_` + +When an expression appears where a statement is expected, the compiler assigns +it to a throwaway variable. It used to use the name `_`, which would clobber a +variable of that name in the user's code (#309). It now uses an autogenerated +`_scrap_N` name. + +```moonscript +_ = 5 +tbl.field +print _ +``` + +**Before:** + +```lua +local _ = 5 +_ = tbl.field +return print(_) +``` + +**After:** + +```lua +local _ = 5 +local _scrap_0 = tbl.field +return print(_) +``` + +### `local` in a class body is hoisted + +A `local` declaration inside a class body was written out near the bottom of the +generated `do` block, after the methods had already been compiled. Methods +referencing the name would close over the outer or global name instead of the +class local (#459). The declaration is now hoisted to the top of the class body, +placed after the reference to the parent class so a body local can shadow the +parent's name. + +```moonscript +class Counter + local count + count = 0 + + inc: => count += 1 +``` + +## Bug Fixes + +* Updated all compiler thrown errors to ensure they include positional + information so the error messages are more informative +* Trailing `continue` in a loop body generated invalid Lua (`break` was + followed by more statements) +* `a, b = x\some_method` and other assignments of a single complex value to + multiple names silently dropped every name after the first +* A `\stub` without a base crashed the compiler with an internal error. Inside a + `with` block it now uses the `with` value, and outside of one it reports + `Short-colon syntax must be called within a with block` (#428) +* `continue` outside of a loop is now a compile error with a line number instead + of an internal error with a traceback +* Destructuring against the result of an `if`, `switch`, `for`, `while`, `do`, + `with`, or comprehension declared the names in the wrong scope (#449, #411, + #391, #451) +* Destructuring against a receiver that can not be indexed directly, like `...`, + `nil`, `not thing`, `#thing`, or a table literal, generated invalid Lua +* An expression inside a string interpolation that can't be parsed now throws a + parse error instead of putting the malformed code as raw characters in the + string +* Fixed broken `moonc --version` which reported missing argument instead of + printing version (#471) +* Errors raised without a position now report the position of the statement + being compiled, instead of no position at all +* An internal compiler error no longer throws a second error while trying to + report the first one + +## Binaries + +* The static binaries now report build information with `--version`: + + ``` + $ moon --version + MoonScript version 0.7.0 (static build) + Runtime: LuaJIT 2.1.1748459687 + Commit: v0.7.0 + Built: 2026-07-24T09:07:45-07:00 + ``` + +* LuaJIT builds are now included alongside the Lua 5.1 builds +* Linux arm64 builds are now included + +## New Parser in Testing + +The next version of MoonScript will likely include the [new C +parser](https://github.com/leafo/moonscript-parser) generated by +[pgen](https://github.com/leafo/pgen), replacing LPeg. Early testing shows the +new parser is be about 5x faster. + +Setting the `MOONSCRIPT_PARSER=pgen` environment variable will make the +compiler parse with the `moonscript_parser` module instead of building the LPeg +grammar at runtime. This is opt in and experimental, the LPeg grammar is still +the default + # MoonScript v0.6.0 (2026-01-10) ## New Features From b0fc077344b3bd3dc6fd503eee0ea05cd604f0c6 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 26 Jul 2026 11:05:05 -0700 Subject: [PATCH 549/554] update docs --- docs/command_line.md | 5 ++-- docs/reference.md | 61 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 3 deletions(-) diff --git a/docs/command_line.md b/docs/command_line.md index 0d69f4da..82bb215b 100644 --- a/docs/command_line.md +++ b/docs/command_line.md @@ -150,9 +150,8 @@ that are nested. ### Linter `moonc` contains a [lint][1] tool for statically detecting potential problems -with code. The linter has two tests: detects accessed global variables, -detect unused declared variables. If the linter detects any issues with a file, -the program will exit with a status of `1`. +with code. If the linter detects any issues with a file, the program will exit +with a status of `1`. You can execute the linter with the `-l` flag. When the linting flag is provided only linting takes place and no compiled code is generated. diff --git a/docs/reference.md b/docs/reference.md index b95e8faf..293165a1 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -212,6 +212,49 @@ some_args = (x=100, y=x+1000) -> print x + y ``` +### Argument Destructuring + +An argument can be written as a table literal to +[destructure](#destructuring_assignment) the value that is passed in. The names +in the table literal become local variables in the body of the function. + +```moon +send_message = ({:sender, :recipient, :body}) -> + print "#{sender} -> #{recipient}: #{body}" + +send_message { + sender: "leaf" + recipient: "world" + body: "hello" +} +``` + +Any pattern that can be used in a destructuring assignment can be used here, +including positional names and nested tables: + +```moon +draw = ({label, pos: {x, y}}) -> + print label, x, y + +draw { "origin", pos: {0, 0} } +``` + +Destructured arguments can be mixed with regular arguments, argument defaults, +and `...`: + +```moon +render = (name, {:width, :height} = {width: 100, height: 50}, ...) -> + print name, width, height, ... +``` + +Using a fat arrow, the pattern can assign directly to properties of the object. +This is convenient for a constructor: + +```moon +class Point + new: ({x: @x, y: @y}) => +``` + ### Considerations Because of the expressive parentheses-less way of calling functions, some @@ -1420,6 +1463,13 @@ extract by mixing the syntax: {:mix, :max, random: rand } = math ``` +The extracted values don't have to be assigned to plain names. Anything that can +go on the left hand side of an assignment works, like properties and indexes: + +```moon +{x: @x, y: obj.y, z: obj["z"]} = point +``` + ### Destructuring In Other Places Destructuring can also show up in places where an assignment implicitly takes @@ -1439,6 +1489,17 @@ for {left, right} in *tuples We know each element in the array table is a two item tuple, so we can unpack it directly in the names clause of the for statement using a destructure. +Destructuring can also be mixed with regular names when assigning multiple +values at once: + +```moon +num, {:message} = get_result! +print num, message +``` + +Function arguments can be destructured as well, see [Argument +Destructuring](#argument_destructuring). + ## Function Stubs From d2f397e9401f7d6939dc640c578d124db336e491 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Sun, 26 Jul 2026 11:18:06 -0700 Subject: [PATCH 550/554] delete old moonscript.cmd.args module --- moonscript/cmd/args.lua | 69 ---------------------------------------- moonscript/cmd/args.moon | 47 --------------------------- spec/cmd_spec.moon | 24 -------------- 3 files changed, 140 deletions(-) delete mode 100644 moonscript/cmd/args.lua delete mode 100644 moonscript/cmd/args.moon diff --git a/moonscript/cmd/args.lua b/moonscript/cmd/args.lua deleted file mode 100644 index 68b06fdc..00000000 --- a/moonscript/cmd/args.lua +++ /dev/null @@ -1,69 +0,0 @@ -local unpack -unpack = require("moonscript.util").unpack -local parse_spec -parse_spec = function(spec) - local flags, words - if type(spec) == "table" then - flags, words = unpack(spec), spec - else - flags, words = spec, { } - end - assert("no flags for arguments") - local out = { } - for part in flags:gmatch("%w:?") do - if part:match(":$") then - out[part:sub(1, 1)] = { - value = true - } - else - out[part] = { } - end - end - return out -end -local parse_arguments -parse_arguments = function(spec, args) - spec = parse_spec(spec) - local out = { } - local remaining = { } - local last_flag = nil - for _index_0 = 1, #args do - local _continue_0 = false - repeat - local arg = args[_index_0] - local group = { } - if last_flag then - out[last_flag] = arg - _continue_0 = true - break - end - do - local flag = arg:match("-(%w+)") - if flag then - do - local short_name = spec[flag] - if short_name then - out[short_name] = true - else - for char in flag:gmatch(".") do - out[char] = true - end - end - end - _continue_0 = true - break - end - end - table.insert(remaining, arg) - _continue_0 = true - until true - if not _continue_0 then - break - end - end - return out, remaining -end -return { - parse_arguments = parse_arguments, - parse_spec = parse_spec -} diff --git a/moonscript/cmd/args.moon b/moonscript/cmd/args.moon deleted file mode 100644 index ac65c0e3..00000000 --- a/moonscript/cmd/args.moon +++ /dev/null @@ -1,47 +0,0 @@ -import unpack from require "moonscript.util" -parse_spec = (spec) -> - flags, words = if type(spec) == "table" - unpack(spec), spec - else - spec, {} - - assert "no flags for arguments" - - out = {} - for part in flags\gmatch "%w:?" - if part\match ":$" - out[part\sub 1,1] = { value: true } - else - out[part] = {} - - out - -parse_arguments = (spec, args) -> - spec = parse_spec spec - - out = {} - - remaining = {} - last_flag = nil - - for arg in *args - group = {} - if last_flag - out[last_flag] = arg - continue - - if flag = arg\match "-(%w+)" - if short_name = spec[flag] - out[short_name] = true - else - for char in flag\gmatch "." - out[char] = true - continue - - table.insert remaining, arg - - out, remaining - - - -{ :parse_arguments, :parse_spec } diff --git a/spec/cmd_spec.moon b/spec/cmd_spec.moon index 039973d5..b6e2be6e 100644 --- a/spec/cmd_spec.moon +++ b/spec/cmd_spec.moon @@ -76,30 +76,6 @@ describe "moonc", -> "cool/" }, watcher\get_dirs! - describe "parse args", -> - it "parses spec", -> - import parse_spec from require "moonscript.cmd.args" - spec = parse_spec "lt:o:X" - assert.same { - X: {} - o: {value: true} - t: {value: true} - l: {} - }, spec - - it "parses arguments", -> - import parse_arguments from require "moonscript.cmd.args" - out, res = parse_arguments { - "ga:p" - print: "p" - }, {"hello", "word", "-gap"} - - assert.same { - g: true - a: true - p: true - }, out - describe "stubbed lfs", -> local dirs From 5f3ed228ed01c8978b4f7ce193b0c350e503630f Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Mon, 27 Jul 2026 09:02:45 -0700 Subject: [PATCH 551/554] merge in moonscript-parser, delete lpeg parser --- .github/workflows/binaries.yml | 6 +- .github/workflows/spec.yml | 1 + .gitignore | 5 + CHANGELOG.md | 36 + Makefile | 26 +- README.md | 10 + bin/binaries/moonscript.c | 4 + bin/moon-tags | 53 +- bin/splat.moon | 4 + docs/api.md | 4 + gen_rockspec.sh | 1 + moonscript-dev-1.rockspec | 8 +- moonscript/compile/value.lua | 4 +- moonscript/parse.lua | 276 +- moonscript/parse.moon | 395 +- moonscript/parse/env.lua | 70 - moonscript/parse/env.moon | 51 - moonscript/parse/errors.lua | 121 + moonscript/parse/grammar.lua | 222 + moonscript/parse/grammar.moon | 385 + moonscript/parse/literals.lua | 39 - moonscript/parse/literals.moon | 38 - moonscript/parse/native.c | 22147 +++++++++++++++++++++++++++++++ moonscript/parse/slow.lua | 13560 +++++++++++++++++++ moonscript/parse/tree.lua | 105 + moonscript/parse/tree.moon | 71 + moonscript/parse/util.lua | 289 - moonscript/parse/util.moon | 185 - moonscript/transform/value.lua | 2 +- moonscript/version.lua | 2 +- moonscript/version.moon | 2 +- spec/helpers.moon | 6 + spec/parser_spec.moon | 151 + spec/use_slow_parser.moon | 7 + 34 files changed, 36960 insertions(+), 1326 deletions(-) create mode 100644 .gitignore delete mode 100644 moonscript/parse/env.lua delete mode 100644 moonscript/parse/env.moon create mode 100644 moonscript/parse/errors.lua create mode 100644 moonscript/parse/grammar.lua create mode 100644 moonscript/parse/grammar.moon delete mode 100644 moonscript/parse/literals.lua delete mode 100644 moonscript/parse/literals.moon create mode 100644 moonscript/parse/native.c create mode 100644 moonscript/parse/slow.lua create mode 100644 moonscript/parse/tree.lua create mode 100644 moonscript/parse/tree.moon delete mode 100644 moonscript/parse/util.lua delete mode 100644 moonscript/parse/util.moon create mode 100644 spec/parser_spec.moon create mode 100644 spec/use_slow_parser.moon diff --git a/.github/workflows/binaries.yml b/.github/workflows/binaries.yml index 8a06cff0..40c3b449 100644 --- a/.github/workflows/binaries.yml +++ b/.github/workflows/binaries.yml @@ -25,7 +25,7 @@ jobs: - name: Generate moonscript.h run: | - bin/splat.moon -l moonscript moonscript moon > moonscript.lua + bin/splat.moon -l moonscript -x moonscript.parse.slow -x moonscript.parse.grammar moonscript moon > moonscript.lua xxd -i moonscript.lua > bin/binaries/moonscript.h - name: Generate moon.h @@ -150,6 +150,7 @@ jobs: -DMOON_BUILD_TIME="\"${{ env.BUILD_TIME }}\"" \ bin/binaries/moon.c \ bin/binaries/moonscript.c \ + moonscript/parse/native.c \ lpeg-1.0.2/lpvm.c \ lpeg-1.0.2/lpcap.c \ lpeg-1.0.2/lptree.c \ @@ -165,6 +166,7 @@ jobs: -DMOON_BUILD_TIME="\"${{ env.BUILD_TIME }}\"" \ bin/binaries/moonc.c \ bin/binaries/moonscript.c \ + moonscript/parse/native.c \ lpeg-1.0.2/lpvm.c \ lpeg-1.0.2/lpcap.c \ lpeg-1.0.2/lptree.c \ @@ -290,6 +292,7 @@ jobs: -DMOON_BUILD_TIME="\"${{ env.BUILD_TIME }}\"" \ bin/binaries/moon.c \ bin/binaries/moonscript.c \ + moonscript/parse/native.c \ lpeg-1.0.2/lpvm.c \ lpeg-1.0.2/lpcap.c \ lpeg-1.0.2/lptree.c \ @@ -305,6 +308,7 @@ jobs: -DMOON_BUILD_TIME="\"${{ env.BUILD_TIME }}\"" \ bin/binaries/moonc.c \ bin/binaries/moonscript.c \ + moonscript/parse/native.c \ lpeg-1.0.2/lpvm.c \ lpeg-1.0.2/lpcap.c \ lpeg-1.0.2/lptree.c \ diff --git a/.github/workflows/spec.yml b/.github/workflows/spec.yml index 91707d8c..ac6d852d 100644 --- a/.github/workflows/spec.yml +++ b/.github/workflows/spec.yml @@ -29,3 +29,4 @@ jobs: - name: test run: | busted -o utfTerminal + busted -o utfTerminal --helper=spec/use_slow_parser.moon diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..eea16b9d --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +*.so +*.o +dist/ +bin/binaries/*.h +bin/binaries/argparse.lua diff --git a/CHANGELOG.md b/CHANGELOG.md index 05087ed2..2ffc8f64 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,39 @@ +# MoonScript dev + +## New parser + +The LPeg parser has been replaced. The grammar is defined in +`moonscript/parse/grammar.moon` and compiled by +[pgen](https://github.com/leafo/pgen) into a native C module, +`moonscript.parse.native`. A pure Lua version of the same grammar is included +as `moonscript.parse.slow`, a drop-in replacement for the native module; it +is not selected automatically. + +Parsing is around 5x faster: + +| Interpreter | LPeg parser | New parser | Speedup | +|-------------|------------:|-----------:|--------:| +| Lua 5.1.5 | 0.947s | 0.180s | 5.3x | +| LuaJIT 2.1 | 0.817s | 0.141s | 5.8x | + +(Parse time for a 405 file, 58,296 line corpus, best of 5 passes.) + +The parser produces the same syntax trees as the LPeg grammar. Other +changes: + +* Parse error messages have a new format: ` at line , column + :` followed by the offending line and a `^` marker, replacing + `Failed to parse: [] >> `. Anything matching on the old error text + will need updating. +* Installing the rock now compiles a C module, so a C compiler is required at + install time. +* `moonscript.parse` no longer exports `build_grammar` and `extract_line`, + and the `moonscript.parse.util`, `moonscript.parse.literals` and + `moonscript.parse.env` modules have been removed. +* The `MOONSCRIPT_PARSER` environment variable is no longer used. +* LPeg is still a dependency: `moonscript.errors` and `bin/moon-tags` use it + for parsing unrelated to MoonScript source. + # MoonScript v0.7.0 (2026-07-26) This update includes a bunch of syntax bug fixes and cleanups, with a few new diff --git a/Makefile b/Makefile index c3c0868b..c841f5de 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,22 @@ LUA_SRC_VERSION ?= 5.1.5 LPEG_VERSION ?= 1.0.2 LFS_VERSION ?= 1_8_0 -.PHONY: test local build watch lint count show test_binary +.PHONY: test local build watch lint count show test_binary generate clean + +clean: + rm -f moonscript/parse/native.so moonscript/parse/native.o + rm -rf dist + +# regenerate the parser from the pgen grammar (requires the pgen to be installed) +generate: build + pgen moonscript/parse/grammar.lua -n moonscript_parse_native \ + -o moonscript/parse/native.c --vendor-errors moonscript/parse/errors.lua + clang-format -style="{ColumnLimit: 0}" -i moonscript/parse/native.c + pgen moonscript/parse/grammar.lua -n moonscript_parse_slow \ + -o moonscript/parse/slow.lua + +moonscript/parse/native.so: moonscript/parse/native.c + gcc -shared -o $@ -O3 -fPIC $< `pkg-config --cflags --libs lua5.1` build: LUA_PATH='$(LUA_PATH_MAKE)' LUA_CPATH='$(LUA_CPATH_MAKE)' $(LUA) bin/moonc moon/ moonscript/ @@ -31,8 +46,9 @@ show: # LUA_PATH_MAKE $(LUA_PATH_MAKE) # LUA_CPATH_MAKE $(LUA_CPATH_MAKE) -test: build - busted +test: build moonscript/parse/native.so + LUA_PATH='$(LUA_PATH_MAKE)' LUA_CPATH='./?.so;$(LUA_CPATH_MAKE)' busted + LUA_PATH='$(LUA_PATH_MAKE)' LUA_CPATH='$(LUA_CPATH_MAKE)' busted --helper=spec/use_slow_parser.moon build_test_outputs: build BUILD=1 busted spec/lang_spec.moon @@ -67,7 +83,7 @@ luafilesystem-$(LFS_VERSION)/src/lfs.c: tar -xzf luafilesystem.tar.gz bin/binaries/moonscript.h: moonscript/*.lua moon/*.lua - bin/splat.moon -l moonscript moonscript moon > moonscript.lua + bin/splat.moon -l moonscript -x moonscript.parse.slow -x moonscript.parse.grammar moonscript moon > moonscript.lua xxd -i moonscript.lua > $@ rm moonscript.lua @@ -93,6 +109,7 @@ dist/moon: lua-$(LUA_SRC_VERSION)/src/liblua.a lpeg-$(LPEG_VERSION)/lptree.c bin -Ibin/binaries/ \ bin/binaries/moon.c \ bin/binaries/moonscript.c \ + moonscript/parse/native.c \ lpeg-$(LPEG_VERSION)/lpvm.c \ lpeg-$(LPEG_VERSION)/lpcap.c \ lpeg-$(LPEG_VERSION)/lptree.c \ @@ -109,6 +126,7 @@ dist/moonc: lua-$(LUA_SRC_VERSION)/src/liblua.a lpeg-$(LPEG_VERSION)/lptree.c lu -Ibin/binaries/ \ bin/binaries/moonc.c \ bin/binaries/moonscript.c \ + moonscript/parse/native.c \ lpeg-$(LPEG_VERSION)/lpvm.c \ lpeg-$(LPEG_VERSION)/lpcap.c \ lpeg-$(LPEG_VERSION)/lptree.c \ diff --git a/README.md b/README.md index b5bb5f92..251205be 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,16 @@ something and you need to re-build the MoonScript with a working version of MoonScript. You can check out the repo in another directory, or install it using LuaRocks to have a separate working version. +### The parser + +The parser is defined as a [pgen](https://github.com/leafo/pgen) grammar in +`moonscript/parse/grammar.moon`, which is compiled to a native C module +(`moonscript/parse/native.c`) and a pure Lua equivalent +(`moonscript/parse/slow.lua`, unused at runtime, kept for a future Lua-only +distribution). Both generated files are checked in. After changing the +grammar, run `make generate` to rebuild them (requires the pgen and +clang-format). + ## Running Tests Tests are written in MoonScript and use [Busted](https://olivinelabs.com/busted/). diff --git a/bin/binaries/moonscript.c b/bin/binaries/moonscript.c index 606242dd..2769008d 100644 --- a/bin/binaries/moonscript.c +++ b/bin/binaries/moonscript.c @@ -23,11 +23,15 @@ void setloaded(lua_State* l, const char* name) { } extern int luaopen_lpeg(lua_State *l); +extern int luaopen_moonscript_parse_native(lua_State *l); LUALIB_API int luaopen_moonscript(lua_State *l) { luaopen_lpeg(l); setloaded(l, "lpeg"); + luaopen_moonscript_parse_native(l); + setloaded(l, "moonscript.parse.native"); + // Load argparse (splat output sets up package.preload) if (luaL_loadbuffer(l, (const char *)argparse_lua, argparse_lua_len, "argparse.lua") == 0) { lua_call(l, 0, 0); diff --git a/bin/moon-tags b/bin/moon-tags index 5f657d55..451fbe22 100755 --- a/bin/moon-tags +++ b/bin/moon-tags @@ -24,34 +24,53 @@ args = parser\parse [v for _, v in ipairs _G.arg] TAGS = {} -- the final output of tags -literals = require "moonscript.parse.literals" -import Indent, simple_string from require "moonscript.parse.util" - -import P, S, C, Cc, Cg, Cb, Ct, Cs, V from require "lpeg" +import P, R, S, C, Cc, Cg, Cb, Ct, Cs, V from require "lpeg" + +Break = P"\r"^-1 * P"\n" +Stop = Break + -1 +AlphaNum = R "az", "AZ", "09", "__" +Name = C R("az", "AZ", "__") * AlphaNum^0 + +-- captures an indentation, returns indent depth +Indent = C(S"\t "^0) / (str) -> + with sum = 0 + for v in str\gmatch "[\t ]" + switch v + when " " + sum += 1 + when "\t" + sum += 4 + +mark = (name) -> (...) -> {name, ...} + +-- quote delimited string, no interpolation parsing since we don't have the +-- full grammar +simple_string = (delim) -> + inner = P("\\#{delim}") + P"\\\\" + (1 - P delim) + C(P delim) * C(inner^0) * P(delim) / mark "string" -- consome the rest of the file -until_end = (1 - literals.Stop)^0 +until_end = (1 - Stop)^0 whitespace = S"\t " -- not including newline ignore_line = Ct until_end -- tag it for empty line --- NOTE: we disable interpolation parsing since we don't have full grammar -SingleString = simple_string "'", false -DoubleString = simple_string '"', false +SingleString = simple_string "'" +DoubleString = simple_string '"' String = SingleString + DoubleString -- we have to do this double Ct to capture both the full line and the grouped captures Type = (name) -> Cg Cc(name), "type" Line = (type_name, p) -> Ct C Ct Cg(Indent, "indent") * p * Type type_name -method = P { P"=>" + P(1 - literals.Stop) * V(1) } -func = P { P"->" + P"=>" + P(1 - literals.Stop) * V(1) } +method = P { P"=>" + P(1 - Stop) * V(1) } +func = P { P"->" + P"=>" + P(1 - Stop) * V(1) } self_prefix = Cg(P("@") * Cc(true), "self") -- this matches end-of-file return table convention for module files to figure -- out what names are exported export_list = Ct P"{" * P { - P"}" + ((P":" * literals.Name) + (P(1) - P"}")) * V(1) + P"}" + ((P":" * Name) + (P(1) - P"}")) * V(1) } eof_exports = P { export_list * S(" \t\r\n")^0 * P(-1) + P(1) * V(1) } @@ -59,11 +78,11 @@ eof_exports = P { export_list * S(" \t\r\n")^0 * P(-1) + P(1) * V(1) } -- convert a parsed string to the value the string represents StringVal = C(String) / (str) -> loadstring("return " .. str)() -class_line = Line "class", P"class" * whitespace^1 * Cg(literals.Name, "tag") * until_end -class_property = Line "property", self_prefix^-1 * Cg(literals.Name, "tag") * P":" * whitespace^0 * Cg(String, "value")^0 * until_end -class_method = Line("method", P("@")^-1 * Cg(literals.Name, "tag") * P":" * method) * until_end -function_def = Line("function", Cg(literals.Name, "tag") * whitespace^0 * P"=" * func) * until_end -lapis_route = Line "lapis-route", P"[" * Cg(literals.Name + StringVal, "tag") * P":" * whitespace^0 * Cg(String, "route") * whitespace^0 * P("]:") * until_end +class_line = Line "class", P"class" * whitespace^1 * Cg(Name, "tag") * until_end +class_property = Line "property", self_prefix^-1 * Cg(Name, "tag") * P":" * whitespace^0 * Cg(String, "value")^0 * until_end +class_method = Line("method", P("@")^-1 * Cg(Name, "tag") * P":" * method) * until_end +function_def = Line("function", Cg(Name, "tag") * whitespace^0 * P"=" * func) * until_end +lapis_route = Line "lapis-route", P"[" * Cg(Name + StringVal, "tag") * P":" * whitespace^0 * Cg(String, "route") * whitespace^0 * P("]:") * until_end line_types = class_line + class_method + class_property + function_def @@ -71,7 +90,7 @@ if args.lapis line_types += lapis_route parse_lines = Ct P { - (line_types + ignore_line) * (P(-1) + literals.Break * V(1)) + (line_types + ignore_line) * (P(-1) + Break * V(1)) } escape_tagaddress = (line_text) -> diff --git a/bin/splat.moon b/bin/splat.moon index d6127042..93d8a2f2 100755 --- a/bin/splat.moon +++ b/bin/splat.moon @@ -9,6 +9,7 @@ normalize = (path) -> parser = argparse "splat.moon", "Concatenate a collection of Lua modules into a single file" parser\option("--load -l", "Module names that will be load on require")\count "*" +parser\option("--exclude -x", "Module names to leave out of the output")\count "*" parser\flag("--strip-prefix -s", "Strip directory prefix from module names") parser\argument("directories", "Directories to scan for Lua modules")\args "+" @@ -54,12 +55,15 @@ write_module = (name, text) -> print " "..line print "end" +exclude = {name, true for name in *args.exclude} + modules = {} for dir in *dirs files = scan_directory dir, "%.lua$" prefix = strip_prefix and normalize(dir) or nil chunks = for path in *files module_name = path_to_module_name path, prefix + continue if exclude[module_name] content = io.open(path)\read"*a" modules[module_name] = true {module_name, content} diff --git a/docs/api.md b/docs/api.md index 56425264..205556a1 100644 --- a/docs/api.md +++ b/docs/api.md @@ -130,3 +130,7 @@ unless lua_code -- our code is ready print lua_code ``` + +On a parse failure `parse.string` returns `nil` and a multi-line error string +of the form ` at line , column :` followed by the offending +source line and a `^` position marker. diff --git a/gen_rockspec.sh b/gen_rockspec.sh index b4faabd0..cf20ce98 100755 --- a/gen_rockspec.sh +++ b/gen_rockspec.sh @@ -5,3 +5,4 @@ for file in $(find moonscript moon | grep 'lua$'); do echo "[\"$MODULE\"] = \"$file\"," done +echo '["moonscript.parse.native"] = { sources = {"moonscript/parse/native.c"} },' diff --git a/moonscript-dev-1.rockspec b/moonscript-dev-1.rockspec index b094bfaf..3571adb8 100644 --- a/moonscript-dev-1.rockspec +++ b/moonscript-dev-1.rockspec @@ -39,9 +39,11 @@ build = { ["moonscript.errors"] = "moonscript/errors.lua", ["moonscript.line_tables"] = "moonscript/line_tables.lua", ["moonscript.parse"] = "moonscript/parse.lua", - ["moonscript.parse.env"] = "moonscript/parse/env.lua", - ["moonscript.parse.literals"] = "moonscript/parse/literals.lua", - ["moonscript.parse.util"] = "moonscript/parse/util.lua", + ["moonscript.parse.errors"] = "moonscript/parse/errors.lua", + ["moonscript.parse.grammar"] = "moonscript/parse/grammar.lua", + ["moonscript.parse.native"] = { sources = {"moonscript/parse/native.c"} }, + ["moonscript.parse.slow"] = "moonscript/parse/slow.lua", + ["moonscript.parse.tree"] = "moonscript/parse/tree.lua", ["moonscript.transform"] = "moonscript/transform.lua", ["moonscript.transform.accumulator"] = "moonscript/transform/accumulator.lua", ["moonscript.transform.class"] = "moonscript/transform/class.lua", diff --git a/moonscript/compile/value.lua b/moonscript/compile/value.lua index 30986551..0a43456c 100644 --- a/moonscript/compile/value.lua +++ b/moonscript/compile/value.lua @@ -92,10 +92,10 @@ return { scoped = function(self, node) local _, before, value, after _, before, value, after = node[1], node[2], node[3], node[4] - _ = before and before:call(self) + local _scrap_0 = before and before:call(self) do local _with_0 = self:value(value) - _ = after and after:call(self) + local _scrap_1 = after and after:call(self) return _with_0 end end, diff --git a/moonscript/parse.lua b/moonscript/parse.lua index 6734eb3c..82972cc4 100644 --- a/moonscript/parse.lua +++ b/moonscript/parse.lua @@ -1,264 +1,26 @@ -local debug_grammar = false -local lpeg = require("lpeg") -lpeg.setmaxstack(10000) -local err_msg = "Failed to parse:%s\n [%d] >> %s" -local Stack -Stack = require("moonscript.data").Stack -local trim, pos_to_line, get_line -do - local _obj_0 = require("moonscript.util") - trim, pos_to_line, get_line = _obj_0.trim, _obj_0.pos_to_line, _obj_0.get_line -end -local unpack -unpack = require("moonscript.util").unpack -local wrap_env -wrap_env = require("moonscript.parse.env").wrap_env -local R, S, V, P, C, Ct, Cmt, Cg, Cb, Cc -R, S, V, P, C, Ct, Cmt, Cg, Cb, Cc = lpeg.R, lpeg.S, lpeg.V, lpeg.P, lpeg.C, lpeg.Ct, lpeg.Cmt, lpeg.Cg, lpeg.Cb, lpeg.Cc -local White, Break, Stop, Comment, Space, SomeSpace, SpaceBreak, EmptyLine, AlphaNum, Num, Shebang, L, _Name -do - local _obj_0 = require("moonscript.parse.literals") - White, Break, Stop, Comment, Space, SomeSpace, SpaceBreak, EmptyLine, AlphaNum, Num, Shebang, L, _Name = _obj_0.White, _obj_0.Break, _obj_0.Stop, _obj_0.Comment, _obj_0.Space, _obj_0.SomeSpace, _obj_0.SpaceBreak, _obj_0.EmptyLine, _obj_0.AlphaNum, _obj_0.Num, _obj_0.Shebang, _obj_0.L, _obj_0.Name -end -local SpaceName = Space * _Name -Num = Space * (Num / function(v) - return { - "number", - v - } -end) -local Indent, Cut, ensure, extract_line, mark, pos, flatten_or_mark, is_assignable, check_assignable, format_assign, format_single_assign, sym, symx, simple_string, wrap_func_arg, join_chain, wrap_decorator, check_lua_string, self_assign, got -do - local _obj_0 = require("moonscript.parse.util") - Indent, Cut, ensure, extract_line, mark, pos, flatten_or_mark, is_assignable, check_assignable, format_assign, format_single_assign, sym, symx, simple_string, wrap_func_arg, join_chain, wrap_decorator, check_lua_string, self_assign, got = _obj_0.Indent, _obj_0.Cut, _obj_0.ensure, _obj_0.extract_line, _obj_0.mark, _obj_0.pos, _obj_0.flatten_or_mark, _obj_0.is_assignable, _obj_0.check_assignable, _obj_0.format_assign, _obj_0.format_single_assign, _obj_0.sym, _obj_0.symx, _obj_0.simple_string, _obj_0.wrap_func_arg, _obj_0.join_chain, _obj_0.wrap_decorator, _obj_0.check_lua_string, _obj_0.self_assign, _obj_0.got -end -local build_grammar = wrap_env(debug_grammar, function(root) - local _indent = Stack(0) - local _do_stack = Stack(0) - local state = { - last_pos = 0 - } - local check_indent - check_indent = function(str, pos, indent) - state.last_pos = pos - return _indent:top() == indent - end - local advance_indent - advance_indent = function(str, pos, indent) - local top = _indent:top() - if top ~= -1 and indent > top then - _indent:push(indent) - return true - end - end - local push_indent - push_indent = function(str, pos, indent) - _indent:push(indent) - return true - end - local pop_indent - pop_indent = function() - assert(_indent:pop(), "unexpected outdent") - return true - end - local check_do - check_do = function(str, pos, do_node) - local top = _do_stack:top() - if top == nil or top then - return true, do_node - end - return false - end - local disable_do - disable_do = function() - _do_stack:push(false) - return true - end - local pop_do - pop_do = function() - assert(_do_stack:pop() ~= nil, "unexpected do pop") - return true - end - local DisableDo = Cmt("", disable_do) - local PopDo = Cmt("", pop_do) - local keywords = { } - local key - key = function(chars) - keywords[chars] = true - return Space * chars * -AlphaNum - end - local op - op = function(chars) - local patt = Space * C(chars) - if chars:match("^%w*$") then - keywords[chars] = true - patt = patt * -AlphaNum - end - return patt - end - local Name = Cmt(SpaceName, function(str, pos, name) - if keywords[name] then - return false - end - return true - end) / trim - local SelfName = Space * "@" * ("@" * (_Name / mark("self_class") + Cc("self.__class")) + _Name / mark("self") + Cc("self")) - local KeyName = SelfName + Space * _Name / mark("key_literal") - local VarArg = Space * P("...") / trim - local g = P({ - root or File, - File = Shebang ^ -1 * (Block + Ct("")), - Block = Ct(Line * (Break ^ 1 * Line) ^ 0), - CheckIndent = Cmt(Indent, check_indent), - Line = (CheckIndent * Statement + Space * L(Stop)), - Statement = pos(Import + While + With + For + ForEach + Switch + Return + Local + Export + BreakLoop + Ct(ExpList) * (Update + Assign) ^ -1 / format_assign) * Space * ((key("if") * Exp * (key("else") * Exp) ^ -1 * Space / mark("if") + key("unless") * Exp / mark("unless") + CompInner / mark("comprehension")) * Space) ^ -1 / wrap_decorator, - Body = Space ^ -1 * Break * EmptyLine ^ 0 * InBlock + Ct(Statement), - Advance = L(Cmt(Indent, advance_indent)), - PushIndent = Cmt(Indent, push_indent), - PreventIndent = Cmt(Cc(-1), push_indent), - PopIndent = Cmt("", pop_indent), - InBlock = Advance * Block * PopIndent, - Local = key("local") * ((op("*") + op("^")) / mark("declare_glob") + Ct(NameList) / mark("declare_with_shadows")), - Import = key("import") * Ct(ImportNameList) * SpaceBreak ^ 0 * key("from") * Exp / mark("import"), - ImportName = (sym("\\") * Ct(Cc("colon") * Name) + Name), - ImportNameList = SpaceBreak ^ 0 * ImportName * ((SpaceBreak ^ 1 + sym(",") * SpaceBreak ^ 0) * ImportName) ^ 0, - BreakLoop = Ct(key("break") / trim) + Ct(key("continue") / trim), - Return = key("return") * (ExpListLow / mark("explist") + C("")) / mark("return"), - WithExp = Ct(ExpList) * Assign ^ -1 / format_assign, - With = key("with") * DisableDo * ensure(WithExp, PopDo) * key("do") ^ -1 * Body / mark("with"), - Switch = key("switch") * DisableDo * ensure(Exp, PopDo) * key("do") ^ -1 * Space ^ -1 * Break * SwitchBlock / mark("switch"), - SwitchBlock = EmptyLine ^ 0 * Advance * Ct(SwitchCase * (Break ^ 1 * SwitchCase) ^ 0 * (Break ^ 1 * SwitchElse) ^ -1) * PopIndent, - SwitchCase = key("when") * Ct(ExpList) * key("then") ^ -1 * Body / mark("case"), - SwitchElse = key("else") * Body / mark("else"), - IfCond = Exp * Assign ^ -1 / format_single_assign, - IfElse = (Break * EmptyLine ^ 0 * CheckIndent) ^ -1 * key("else") * Body / mark("else"), - IfElseIf = (Break * EmptyLine ^ 0 * CheckIndent) ^ -1 * key("elseif") * pos(IfCond) * key("then") ^ -1 * Body / mark("elseif"), - If = key("if") * IfCond * key("then") ^ -1 * Body * IfElseIf ^ 0 * IfElse ^ -1 / mark("if"), - Unless = key("unless") * IfCond * key("then") ^ -1 * Body * IfElseIf ^ 0 * IfElse ^ -1 / mark("unless"), - While = key("while") * DisableDo * ensure(Exp, PopDo) * key("do") ^ -1 * Body / mark("while"), - For = key("for") * DisableDo * ensure(Name * sym("=") * Ct(Exp * sym(",") * Exp * (sym(",") * Exp) ^ -1), PopDo) * key("do") ^ -1 * Body / mark("for"), - ForEach = key("for") * Ct(AssignableNameList) * key("in") * DisableDo * ensure(Ct(sym("*") * Exp / mark("unpack") + ExpList), PopDo) * key("do") ^ -1 * Body / mark("foreach"), - Do = key("do") * Body / mark("do"), - Comprehension = sym("[") * Exp * CompInner * sym("]") / mark("comprehension"), - TblComprehension = sym("{") * Ct(Exp * (sym(",") * Exp) ^ -1) * CompInner * sym("}") / mark("tblcomprehension"), - CompInner = Ct((CompForEach + CompFor) * CompClause ^ 0), - CompForEach = key("for") * Ct(AssignableNameList) * 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=") + sym("&=") + sym("|=") + sym(">>=") + sym("<<=")) / trim) * Exp / mark("update"), - CharOperators = Space * C(S("+-*/%^><|&")), - WordOperators = op("or") + op("and") + op("<=") + op(">=") + op("~=") + op("!=") + op("==") + op("..") + op("<<") + op(">>") + op("//"), - BinaryOperator = (WordOperators + CharOperators) * SpaceBreak ^ 0, - Assignable = Cmt(Chain, check_assignable) + Name + SelfName, - Exp = Ct(Value * (BinaryOperator * Value) ^ 0) / flatten_or_mark("exp"), - SimpleValue = If + Unless + Switch + With + ClassDecl + ForEach + For + While + Cmt(Do, check_do) + sym("-") * -SomeSpace * Exp / mark("minus") + sym("#") * Exp / mark("length") + sym("~") * Exp / mark("bitnot") + key("not") * Exp / mark("not") + TblComprehension + TableLit + Comprehension + FunLit + Num, - ChainValue = (Chain + Callable) * Ct(InvokeArgs ^ -1) / join_chain, - Value = pos(SimpleValue + Ct(KeyValueList) / mark("table") + ChainValue + String), - SliceValue = Exp, - String = Space * DoubleString + Space * SingleString + LuaString, - SingleString = simple_string("'"), - DoubleString = simple_string('"', true), - LuaString = Cg(LuaStringOpen, "string_open") * Cb("string_open") * Break ^ -1 * C((1 - Cmt(C(LuaStringClose) * Cb("string_open"), check_lua_string)) ^ 0) * LuaStringClose / mark("string"), - LuaStringOpen = sym("[") * P("=") ^ 0 * "[" / trim, - LuaStringClose = "]" * P("=") ^ 0 * "]", - Callable = pos(Name / mark("ref")) + SelfName + VarArg + Parens / mark("parens"), - Parens = sym("(") * SpaceBreak ^ 0 * Exp * SpaceBreak ^ 0 * sym(")"), - FnArgs = symx("(") * SpaceBreak ^ 0 * Ct(FnArgsExpList ^ -1) * SpaceBreak ^ 0 * sym(")") + sym("!") * -P("=") * Ct(""), - FnArgsExpList = Exp * ((Break + sym(",")) * White * Exp) ^ 0, - Chain = (Callable + String + -S(".\\")) * ChainItems / mark("chain") + Space * (DotChainItem * ChainItems ^ -1 + ColonChain) / mark("chain"), - ChainItems = ChainItem ^ 1 * ColonChain ^ -1 + ColonChain, - ChainItem = Invoke + DotChainItem + Slice + symx("[") * Exp / mark("index") * sym("]"), - DotChainItem = symx(".") * _Name / mark("dot"), - ColonChainItem = symx("\\") * _Name / mark("colon"), - ColonChain = ColonChainItem * (Invoke * ChainItems ^ -1) ^ -1, - Slice = symx("[") * (SliceValue + Cc(1)) * sym(",") * (SliceValue + Cc("")) * (sym(",") * SliceValue) ^ -1 * sym("]") / mark("slice"), - Invoke = FnArgs / mark("call") + SingleString / wrap_func_arg + DoubleString / wrap_func_arg + L(P("[")) * LuaString / wrap_func_arg, - TableValue = KeyValue + Ct(Exp), - TableLit = sym("{") * Ct(TableValueList ^ -1 * sym(",") ^ -1 * (SpaceBreak * TableLitLine * (sym(",") ^ -1 * SpaceBreak * TableLitLine) ^ 0 * sym(",") ^ -1) ^ -1) * White * sym("}") / mark("table"), - TableValueList = TableValue * (sym(",") * TableValue) ^ 0, - TableLitLine = PushIndent * ((TableValueList * PopIndent) + (PopIndent * Cut)) + Space, - TableBlockInner = Ct(KeyValueLine * (SpaceBreak ^ 1 * KeyValueLine) ^ 0), - TableBlock = SpaceBreak ^ 1 * Advance * ensure(TableBlockInner, PopIndent) / mark("table"), - ClassDecl = key("class") * -P(":") * (Assignable + Cc(nil)) * (key("extends") * PreventIndent * ensure(Exp, PopIndent) + C("")) ^ -1 * (ClassBlock + Ct("")) / mark("class"), - ClassBlock = SpaceBreak ^ 1 * Advance * Ct(ClassLine * (SpaceBreak ^ 1 * ClassLine) ^ 0) * PopIndent, - ClassLine = CheckIndent * ((KeyValueList / mark("props") + Statement / mark("stm") + Exp / mark("stm")) * sym(",") ^ -1), - Export = key("export") * (Cc("class") * ClassDecl + op("*") + op("^") + Ct(NameList) * (sym("=") * Ct(ExpListLow)) ^ -1) / mark("export"), - KeyValue = (sym(":") * -SomeSpace * Name * lpeg.Cp()) / self_assign + Ct((KeyName + sym("[") * Exp * sym("]") + Space * DoubleString + Space * SingleString) * symx(":") * (Exp + TableBlock + SpaceBreak ^ 1 * Exp)), - KeyValueList = KeyValue * (sym(",") * KeyValue) ^ 0, - KeyValueLine = CheckIndent * KeyValueList * sym(",") ^ -1, - FnArgsDef = sym("(") * White * Ct(FnArgDefList ^ -1) * (key("using") * Ct(NameList + Space * "nil") + Ct("")) * White * sym(")") + Ct("") * Ct(""), - FnArgDefList = FnArgDef * ((sym(",") + Break) * White * FnArgDef) ^ 0 * ((sym(",") + Break) * White * Ct(VarArg)) ^ 0 + Ct(VarArg), - FnArgDef = Ct((Name + SelfName + TableLit) * (sym("=") * Exp) ^ -1), - FunLit = FnArgsDef * (sym("->") * Cc("slim") + sym("=>") * Cc("fat")) * (Body + Ct("")) / mark("fndef"), - NameList = Name * (sym(",") * Name) ^ 0, - NameOrDestructure = Name + TableLit, - AssignableNameList = NameOrDestructure * (sym(",") * NameOrDestructure) ^ 0, - ExpList = Exp * (sym(",") * Exp) ^ 0, - ExpListLow = Exp * ((sym(",") + sym(";")) * Exp) ^ 0, - InvokeArgs = -P("-") * (ExpList * (sym(",") * (TableBlock + SpaceBreak * Advance * ArgBlock * TableBlock ^ -1) + TableBlock) ^ -1 + TableBlock), - ArgBlock = ArgLine * (sym(",") * SpaceBreak * ArgLine) ^ 0 * PopIndent, - ArgLine = CheckIndent * ExpList - }) - return g, state -end) -local file_parser -file_parser = function() - local g, state = build_grammar() - local file_grammar = White * g * White * -1 - return { - match = function(self, str) - local tree - local _, err = xpcall((function() - tree = file_grammar:match(str) - end), function(err) - return debug.traceback(err, 2) - end) - if type(err) == "string" then - return nil, err - end - if not (tree) then - local msg - local err_pos = state.last_pos - if err then - local node - node, msg = unpack(err) - if msg then - msg = " " .. msg - end - err_pos = node[-1] +local errors = require("moonscript.parse.errors") +local parser = require("moonscript.parse.native") +return { + string = function(str) + local ok, result, label, err_pos = pcall(parser.parse, str) + if not (ok) then + if type(result) == "table" then + local node, msg + node, msg = result[1], result[2] + local node_pos = type(node) == "table" and node[-1] + if node_pos then + return nil, errors.format(str, node_pos, msg) end - local line_no = pos_to_line(str, err_pos) - local line_str = get_line(str, line_no) or "" - return nil, err_msg:format(msg or "", line_no, trim(line_str)) + return nil, "failed to parse: " .. tostring(msg) end - return tree - end - } -end -local native_parser -local get_native_parser -get_native_parser = function() - if native_parser == nil then - if os.getenv("MOONSCRIPT_PARSER") == "pgen" then - native_parser = require("moonscript_parser") - else - native_parser = false + return nil, tostring(result) end - end - return native_parser -end -return { - extract_line = extract_line, - build_grammar = build_grammar, - string = function(str) - do - local native = get_native_parser() - if native then - return native.string(str) - else - return file_parser():match(str) + if not (result) then + if err_pos then + return nil, errors.format(str, err_pos, label or "failed to parse") end + return nil, "failed to parse" end + return result end } diff --git a/moonscript/parse.moon b/moonscript/parse.moon index f9ae314c..b49e93b2 100644 --- a/moonscript/parse.moon +++ b/moonscript/parse.moon @@ -1,378 +1,39 @@ -debug_grammar = false -lpeg = require "lpeg" +-- MoonScript parser interface. The parser itself is generated from the +-- grammar in moonscript/parse/grammar.moon by pgen +-- (https://github.com/leafo/pgen), see `make generate`. +-- moonscript/parse/slow.lua is the same grammar generated as pure Lua, a +-- drop-in for distributions that can't build the C module. -lpeg.setmaxstack 10000 -- whoa - -err_msg = "Failed to parse:%s\n [%d] >> %s" - -import Stack from require "moonscript.data" -import trim, pos_to_line, get_line from require "moonscript.util" -import unpack from require "moonscript.util" -import wrap_env from require "moonscript.parse.env" - -{ - :R, :S, :V, :P, :C, :Ct, :Cmt, :Cg, :Cb, :Cc -} = lpeg - -{ - :White, :Break, :Stop, :Comment, :Space, :SomeSpace, :SpaceBreak, :EmptyLine, - :AlphaNum, :Num, :Shebang, :L - Name: _Name -} = require "moonscript.parse.literals" - -SpaceName = Space * _Name -Num = Space * (Num / (v) -> {"number", v}) +errors = require "moonscript.parse.errors" +parser = require "moonscript.parse.native" { - :Indent, :Cut, :ensure, :extract_line, :mark, :pos, :flatten_or_mark, - :is_assignable, :check_assignable, :format_assign, :format_single_assign, - :sym, :symx, :simple_string, :wrap_func_arg, :join_chain, - :wrap_decorator, :check_lua_string, :self_assign, :got - -} = require "moonscript.parse.util" - - -build_grammar = wrap_env debug_grammar, (root) -> - _indent = Stack 0 - _do_stack = Stack 0 - - state = { - -- last pos we saw, used to report error location - last_pos: 0 - } - - check_indent = (str, pos, indent) -> - state.last_pos = pos - _indent\top! == indent - - advance_indent = (str, pos, indent) -> - top = _indent\top! - if top != -1 and indent > top - _indent\push indent - true - - push_indent = (str, pos, indent) -> - _indent\push indent - true - - pop_indent = -> - assert _indent\pop!, "unexpected outdent" - true - - check_do = (str, pos, do_node) -> - top = _do_stack\top! - if top == nil or top - return true, do_node - false - - disable_do = -> - _do_stack\push false - true - - pop_do = -> - assert _do_stack\pop! != nil, "unexpected do pop" - true - - DisableDo = Cmt "", disable_do - PopDo = Cmt "", pop_do - - keywords = {} - key = (chars) -> - keywords[chars] = true - Space * chars * -AlphaNum - - op = (chars) -> - patt = Space * C chars - -- it's a word, treat like keyword - if chars\match "^%w*$" - keywords[chars] = true - patt *= -AlphaNum - - patt - - Name = Cmt(SpaceName, (str, pos, name) -> - return false if keywords[name] - true - ) / trim - - SelfName = Space * "@" * ( - "@" * (_Name / mark"self_class" + Cc"self.__class") + - _Name / mark"self" + - Cc"self" -- @ by itself - ) - - KeyName = SelfName + Space * _Name / mark"key_literal" - VarArg = Space * P"..." / trim - - g = P { - root or File - File: Shebang^-1 * (Block + Ct"") - Block: Ct(Line * (Break^1 * Line)^0) - CheckIndent: Cmt(Indent, check_indent), -- validates line is in correct indent - Line: (CheckIndent * Statement + Space * L(Stop)) - - Statement: pos( - Import + While + With + For + ForEach + Switch + Return + - Local + Export + BreakLoop + - Ct(ExpList) * (Update + Assign)^-1 / format_assign - ) * Space * (( - -- statement decorators - key"if" * Exp * (key"else" * Exp)^-1 * Space / mark"if" + - key"unless" * Exp / mark"unless" + - CompInner / mark"comprehension" - ) * Space)^-1 / wrap_decorator - - Body: Space^-1 * Break * EmptyLine^0 * InBlock + Ct(Statement) -- either a statement, or an indented block - - Advance: L Cmt(Indent, advance_indent) -- Advances the indent, gives back whitespace for CheckIndent - PushIndent: Cmt(Indent, push_indent) - PreventIndent: Cmt(Cc(-1), push_indent) - PopIndent: Cmt("", pop_indent) - InBlock: Advance * Block * PopIndent - - Local: key"local" * ((op"*" + op"^") / mark"declare_glob" + Ct(NameList) / mark"declare_with_shadows") - - Import: key"import" * Ct(ImportNameList) * SpaceBreak^0 * key"from" * Exp / mark"import" - ImportName: (sym"\\" * Ct(Cc"colon" * Name) + Name) - ImportNameList: SpaceBreak^0 * ImportName * ((SpaceBreak^1 + sym"," * SpaceBreak^0) * ImportName)^0 - - BreakLoop: Ct(key"break"/trim) + Ct(key"continue"/trim) - - Return: key"return" * (ExpListLow/mark"explist" + C"") / mark"return" - - WithExp: Ct(ExpList) * Assign^-1 / format_assign - With: key"with" * DisableDo * ensure(WithExp, PopDo) * key"do"^-1 * Body / mark"with" - - Switch: key"switch" * DisableDo * ensure(Exp, PopDo) * key"do"^-1 * Space^-1 * Break * SwitchBlock / mark"switch" - - SwitchBlock: EmptyLine^0 * Advance * Ct(SwitchCase * (Break^1 * SwitchCase)^0 * (Break^1 * SwitchElse)^-1) * PopIndent - SwitchCase: key"when" * Ct(ExpList) * key"then"^-1 * Body / mark"case" - SwitchElse: key"else" * Body / mark"else" - - IfCond: Exp * Assign^-1 / format_single_assign - - IfElse: (Break * EmptyLine^0 * CheckIndent)^-1 * key"else" * Body / mark"else" - IfElseIf: (Break * EmptyLine^0 * CheckIndent)^-1 * key"elseif" * pos(IfCond) * key"then"^-1 * Body / mark"elseif" - - If: key"if" * IfCond * key"then"^-1 * Body * IfElseIf^0 * IfElse^-1 / mark"if" - Unless: key"unless" * IfCond * key"then"^-1 * Body * IfElseIf^0 * IfElse^-1 / mark"unless" - - While: key"while" * DisableDo * ensure(Exp, PopDo) * key"do"^-1 * Body / mark"while" - - For: key"for" * DisableDo * ensure(Name * sym"=" * Ct(Exp * sym"," * Exp * (sym"," * Exp)^-1), PopDo) * - key"do"^-1 * Body / mark"for" - - ForEach: key"for" * Ct(AssignableNameList) * key"in" * DisableDo * ensure(Ct(sym"*" * Exp / mark"unpack" + ExpList), PopDo) * key"do"^-1 * Body / mark"foreach" - - Do: key"do" * Body / mark"do" - - Comprehension: sym"[" * Exp * CompInner * sym"]" / mark"comprehension" - - TblComprehension: sym"{" * Ct(Exp * (sym"," * Exp)^-1) * CompInner * sym"}" / mark"tblcomprehension" - - CompInner: Ct((CompForEach + CompFor) * CompClause^0) - CompForEach: key"for" * Ct(AssignableNameList) * 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=" + sym"&=" + sym"|=" + sym">>=" + sym"<<=") / trim) * Exp / mark"update" - - CharOperators: Space * C(S"+-*/%^><|&") - WordOperators: op"or" + op"and" + op"<=" + op">=" + op"~=" + op"!=" + op"==" + op".." + op"<<" + op">>" + op"//" - BinaryOperator: (WordOperators + CharOperators) * SpaceBreak^0 - - Assignable: Cmt(Chain, check_assignable) + Name + SelfName - Exp: Ct(Value * (BinaryOperator * Value)^0) / flatten_or_mark"exp" - - SimpleValue: - If + Unless + - Switch + - With + - ClassDecl + - ForEach + For + While + - Cmt(Do, check_do) + - sym"-" * -SomeSpace * Exp / mark"minus" + - sym"#" * Exp / mark"length" + - sym"~" * Exp / mark"bitnot" + - key"not" * Exp / mark"not" + - TblComprehension + - TableLit + - Comprehension + - FunLit + - Num - - -- a function call or an object access - ChainValue: (Chain + Callable) * Ct(InvokeArgs^-1) / join_chain - - Value: pos( - SimpleValue + - Ct(KeyValueList) / mark"table" + - ChainValue + - String) - - SliceValue: Exp - - String: Space * DoubleString + Space * SingleString + LuaString - SingleString: simple_string("'") - DoubleString: simple_string('"', true) - - LuaString: Cg(LuaStringOpen, "string_open") * Cb"string_open" * Break^-1 * - C((1 - Cmt(C(LuaStringClose) * Cb"string_open", check_lua_string))^0) * - LuaStringClose / mark"string" - - LuaStringOpen: sym"[" * P"="^0 * "[" / trim - LuaStringClose: "]" * P"="^0 * "]" - - Callable: pos(Name / mark"ref") + SelfName + VarArg + Parens / mark"parens" - Parens: sym"(" * SpaceBreak^0 * Exp * SpaceBreak^0 * sym")" - - FnArgs: symx"(" * SpaceBreak^0 * Ct(FnArgsExpList^-1) * SpaceBreak^0 * sym")" + sym"!" * -P"=" * Ct"" - FnArgsExpList: Exp * ((Break + sym",") * White * Exp)^0 - - Chain: (Callable + String + -S".\\") * ChainItems / mark"chain" + - Space * (DotChainItem * ChainItems^-1 + ColonChain) / mark"chain" - - ChainItems: ChainItem^1 * ColonChain^-1 + ColonChain - - ChainItem: - Invoke + - DotChainItem + - Slice + - symx"[" * Exp/mark"index" * sym"]" - - DotChainItem: symx"." * _Name/mark"dot" - ColonChainItem: symx"\\" * _Name / mark"colon" - ColonChain: ColonChainItem * (Invoke * ChainItems^-1)^-1 - - Slice: symx"[" * (SliceValue + Cc(1)) * sym"," * (SliceValue + Cc"") * - (sym"," * SliceValue)^-1 *sym"]" / mark"slice" - - Invoke: FnArgs / mark"call" + - SingleString / wrap_func_arg + - DoubleString / wrap_func_arg + - L(P"[") * LuaString / wrap_func_arg - - TableValue: KeyValue + Ct(Exp) - - TableLit: sym"{" * Ct( - TableValueList^-1 * sym","^-1 * - (SpaceBreak * TableLitLine * (sym","^-1 * SpaceBreak * TableLitLine)^0 * sym","^-1)^-1 - ) * White * sym"}" / mark"table" - - TableValueList: TableValue * (sym"," * TableValue)^0 - TableLitLine: PushIndent * ((TableValueList * PopIndent) + (PopIndent * Cut)) + Space - - -- the unbounded table - TableBlockInner: Ct(KeyValueLine * (SpaceBreak^1 * KeyValueLine)^0) - TableBlock: SpaceBreak^1 * Advance * ensure(TableBlockInner, PopIndent) / mark"table" - - ClassDecl: key"class" * -P":" * (Assignable + Cc(nil)) * (key"extends" * PreventIndent * ensure(Exp, PopIndent) + C"")^-1 * (ClassBlock + Ct("")) / mark"class" - - ClassBlock: SpaceBreak^1 * Advance * - Ct(ClassLine * (SpaceBreak^1 * ClassLine)^0) * PopIndent - ClassLine: CheckIndent * (( - KeyValueList / mark"props" + - Statement / mark"stm" + - Exp / mark"stm" - ) * sym","^-1) - - Export: key"export" * ( - Cc"class" * ClassDecl + - op"*" + op"^" + - Ct(NameList) * (sym"=" * Ct(ExpListLow))^-1) / mark"export" - - KeyValue: (sym":" * -SomeSpace * Name * lpeg.Cp!) / self_assign + - Ct( - (KeyName + sym"[" * Exp * sym"]" +Space * DoubleString + Space * SingleString) * - symx":" * - (Exp + TableBlock + SpaceBreak^1 * Exp) - ) - - KeyValueList: KeyValue * (sym"," * KeyValue)^0 - KeyValueLine: CheckIndent * KeyValueList * sym","^-1 - - FnArgsDef: sym"(" * White * Ct(FnArgDefList^-1) * - (key"using" * Ct(NameList + Space * "nil") + Ct"") * - White * sym")" + Ct"" * Ct"" - - FnArgDefList: FnArgDef * ((sym"," + Break) * White * FnArgDef)^0 * ((sym"," + Break) * White * Ct(VarArg))^0 + Ct(VarArg) - FnArgDef: Ct((Name + SelfName + TableLit) * (sym"=" * Exp)^-1) - - FunLit: FnArgsDef * - (sym"->" * Cc"slim" + sym"=>" * Cc"fat") * - (Body + Ct"") / mark"fndef" - - NameList: Name * (sym"," * Name)^0 - NameOrDestructure: Name + TableLit - AssignableNameList: NameOrDestructure * (sym"," * NameOrDestructure)^0 - - ExpList: Exp * (sym"," * Exp)^0 - ExpListLow: Exp * ((sym"," + sym";") * Exp)^0 - - -- open args - InvokeArgs: -P"-" * (ExpList * (sym"," * (TableBlock + SpaceBreak * Advance * ArgBlock * TableBlock^-1) + TableBlock)^-1 + TableBlock) - ArgBlock: ArgLine * (sym"," * SpaceBreak * ArgLine)^0 * PopIndent - ArgLine: CheckIndent * ExpList - } - - g, state - -file_parser = -> - g, state = build_grammar! - file_grammar = White * g * White * -1 - - { - match: (str) => - local tree - _, err = xpcall (-> - tree = file_grammar\match str - ), (err) -> - debug.traceback err, 2 - - -- regular error, let it bubble up - if type(err) == "string" - return nil, err + -- parse a string as a file + -- returns tree, or nil and error message + string: (str) -> + -- grammar transforms run during parse(); format_assign raises + -- error({node, msg}) for invalid assignment targets + ok, result, label, err_pos = pcall parser.parse, str - unless tree - local msg - err_pos = state.last_pos + unless ok + if type(result) == "table" + {node, msg} = result + node_pos = type(node) == "table" and node[-1] - if err - node, msg = unpack err - msg = " " .. msg if msg - err_pos = node[-1] + if node_pos + return nil, errors.format str, node_pos, msg - line_no = pos_to_line str, err_pos - line_str = get_line(str, line_no) or "" - return nil, err_msg\format msg or "", line_no, trim line_str + return nil, "failed to parse: " .. tostring msg - tree - } + -- errors thrown by the parser itself (e.g. the recursion depth limit) + -- are returned like any other parse failure, not raised + return nil, tostring result --- opt in to the compiled parser from the moonscript-parser rock by setting --- MOONSCRIPT_PARSER=pgen in the environment. Fails loudly if the rock --- isn't installed rather than silently using the LPeg parser -local native_parser -get_native_parser = -> - if native_parser == nil - native_parser = if os.getenv("MOONSCRIPT_PARSER") == "pgen" - require "moonscript_parser" - else - false + unless result + if err_pos + return nil, errors.format str, err_pos, label or "failed to parse" - native_parser + return nil, "failed to parse" -{ - :extract_line - :build_grammar - - -- parse a string as a file - -- returns tree, or nil and error message - string: (str) -> - if native = get_native_parser! - native.string str - else - file_parser!\match str + result } - diff --git a/moonscript/parse/env.lua b/moonscript/parse/env.lua deleted file mode 100644 index f805211b..00000000 --- a/moonscript/parse/env.lua +++ /dev/null @@ -1,70 +0,0 @@ -local getfenv, setfenv -do - local _obj_0 = require("moonscript.util") - getfenv, setfenv = _obj_0.getfenv, _obj_0.setfenv -end -local wrap_env -wrap_env = function(debug, fn) - local V, Cmt - do - local _obj_0 = require("lpeg") - V, Cmt = _obj_0.V, _obj_0.Cmt - end - local env = getfenv(fn) - local wrap_name = V - if debug then - local indent = 0 - local indent_char = " " - local iprint - iprint = function(...) - local args = table.concat((function(...) - local _accum_0 = { } - local _len_0 = 1 - local _list_0 = { - ... - } - for _index_0 = 1, #_list_0 do - local a = _list_0[_index_0] - _accum_0[_len_0] = tostring(a) - _len_0 = _len_0 + 1 - end - return _accum_0 - end)(...), ", ") - return io.stderr:write(tostring(indent_char:rep(indent)) .. tostring(args) .. "\n") - end - wrap_name = function(name) - local v = V(name) - v = Cmt("", function(str, pos) - local rest = str:sub(pos, -1):match("^([^\n]*)") - iprint("* " .. tostring(name) .. " (" .. tostring(rest) .. ")") - indent = indent + 1 - return true - end) * Cmt(v, function(str, pos, ...) - iprint(name, true) - indent = indent - 1 - return true, ... - end) + Cmt("", function() - iprint(name, false) - indent = indent - 1 - return false - end) - return v - end - end - return setfenv(fn, setmetatable({ }, { - __index = function(self, name) - local value = env[name] - if value ~= nil then - return value - end - if name:match("^[A-Z][A-Za-z0-9]*$") then - local v = wrap_name(name) - return v - end - return error("unknown variable referenced: " .. tostring(name)) - end - })) -end -return { - wrap_env = wrap_env -} diff --git a/moonscript/parse/env.moon b/moonscript/parse/env.moon deleted file mode 100644 index ea71c3df..00000000 --- a/moonscript/parse/env.moon +++ /dev/null @@ -1,51 +0,0 @@ - -import getfenv, setfenv from require "moonscript.util" - --- all undefined Proper globals are automaticlly converted into lpeg.V -wrap_env = (debug, fn) -> - import V, Cmt from require "lpeg" - - env = getfenv fn - wrap_name = V - - if debug - indent = 0 - indent_char = " " - - iprint = (...) -> - args = table.concat [tostring a for a in *{...}], ", " - io.stderr\write "#{indent_char\rep(indent)}#{args}\n" - - wrap_name = (name) -> - v = V name - v = Cmt("", (str, pos) -> - rest = str\sub(pos, -1)\match "^([^\n]*)" - - iprint "* #{name} (#{rest})" - indent += 1 - true - ) * Cmt(v, (str, pos, ...) -> - iprint name, true - indent -= 1 - true, ... - ) + Cmt("", -> - iprint name, false - indent -= 1 - false - ) - - v - - setfenv fn, setmetatable {}, { - __index: (name) => - value = env[name] - return value if value != nil - - if name\match"^[A-Z][A-Za-z0-9]*$" - v = wrap_name name - return v - - error "unknown variable referenced: #{name}" - } - -{ :wrap_env } diff --git a/moonscript/parse/errors.lua b/moonscript/parse/errors.lua new file mode 100644 index 00000000..1ec6c173 --- /dev/null +++ b/moonscript/parse/errors.lua @@ -0,0 +1,121 @@ +local errors = {} + +-- Split subject into array of lines (local helper) +local function splitlines(subject) + local lines = {} + local start = 1 + while true do + local newline_pos = subject:find("\n", start, true) + if newline_pos then + lines[#lines + 1] = subject:sub(start, newline_pos - 1) + start = newline_pos + 1 + else + lines[#lines + 1] = subject:sub(start) + break + end + end + return lines +end + +-- Calculate line number and column from byte position (local helper) +-- Returns: line (1-indexed), column (1-indexed) +local function calcline(subject, pos) + if pos <= 1 then return 1, 1 end + local sub = subject:sub(1, pos - 1) + local line = 1 + local last_newline = 0 + for i = 1, #sub do + if sub:sub(i, i) == "\n" then + line = line + 1 + last_newline = i + end + end + local col = pos - last_newline + return line, col +end + +-- Get the line of text containing the given position (local helper) +-- Returns: line text, column position within that line +local function getline(subject, pos) + -- Find start of line + local line_start = pos + while line_start > 1 and subject:sub(line_start - 1, line_start - 1) ~= "\n" do + line_start = line_start - 1 + end + -- Find end of line + local line_end = pos + while line_end <= #subject and subject:sub(line_end, line_end) ~= "\n" do + line_end = line_end + 1 + end + return subject:sub(line_start, line_end - 1), pos - line_start + 1 +end + +-- Format a complete error message +-- subject: the input string being parsed +-- pos: byte position where error occurred (1-indexed) +-- label: error label from T() or nil +-- opts: optional table with: +-- color: boolean - if true, use ansicolors for colored output +-- context: number - lines to show above and below error line (default: 0) +function errors.format(subject, pos, label, opts) + local line, col = calcline(subject, pos) + local line_text, col_in_line = getline(subject, pos) + local context = opts and opts.context or 0 + + local msg + if opts and opts.color then + local colors = require("ansicolors") + msg = colors("%{bright red}" .. (label or "error") .. "%{reset}") + msg = msg .. colors(" %{dim}at line " .. line .. ", column " .. col .. ":%{reset}\n") + + if context > 0 then + local lines = splitlines(subject) + local start_line = math.max(1, line - context) + local end_line = math.min(#lines, line + context) + local max_line_num = end_line + local line_num_width = #tostring(max_line_num) + + for i = start_line, end_line do + local line_num_str = string.format("%" .. line_num_width .. "d", i) + msg = msg .. colors("%{dim}" .. line_num_str .. " |%{reset} ") .. lines[i] .. "\n" + if i == line then + local prefix_width = line_num_width + 3 + col_in_line - 1 + msg = msg .. string.rep(" ", prefix_width) .. colors("%{bright red}^%{reset}") .. "\n" + end + end + msg = msg:sub(1, -2) -- remove trailing newline + else + msg = msg .. " " .. line_text .. "\n" + msg = msg .. " " .. string.rep(" ", col_in_line - 1) + msg = msg .. colors("%{bright red}^%{reset}") + end + else + msg = string.format("%s at line %d, column %d:\n", + label or "error", line, col) + + if context > 0 then + local lines = splitlines(subject) + local start_line = math.max(1, line - context) + local end_line = math.min(#lines, line + context) + local max_line_num = end_line + local line_num_width = #tostring(max_line_num) + + for i = start_line, end_line do + local line_num_str = string.format("%" .. line_num_width .. "d", i) + msg = msg .. line_num_str .. " | " .. lines[i] .. "\n" + if i == line then + local prefix_width = line_num_width + 3 + col_in_line - 1 + msg = msg .. string.rep(" ", prefix_width) .. "^\n" + end + end + msg = msg:sub(1, -2) -- remove trailing newline + else + msg = msg .. " " .. line_text .. "\n" + msg = msg .. " " .. string.rep(" ", col_in_line - 1) .. "^" + end + end + + return msg +end + +return errors diff --git a/moonscript/parse/grammar.lua b/moonscript/parse/grammar.lua new file mode 100644 index 00000000..5d99cd5d --- /dev/null +++ b/moonscript/parse/grammar.lua @@ -0,0 +1,222 @@ +local pgen = require("pgen") +local P, R, S, V, C, Ct, Cc, Cp, Cg, Cmb, Cmt, Cfn, L +P, R, S, V, C, Ct, Cc, Cp, Cg, Cmb, Cmt, Cfn, L = pgen.P, pgen.R, pgen.S, pgen.V, pgen.C, pgen.Ct, pgen.Cc, pgen.Cp, pgen.Cg, pgen.Cmb, pgen.Cmt, pgen.Cfn, pgen.L +local ind = pgen.indenter({ + tab_width = 4, + initial = 0 +}) +local dos = pgen.indenter({ + initial = 1 +}) +local DisableDo = dos.cpush(0) +local PopDo = dos.pop +local CheckDo = dos.ctop("ne", 0) +local AlphaNum = R("az", "AZ", "09", "__") +local keyword_words = { + "continue", + "extends", + "elseif", + "export", + "import", + "return", + "switch", + "unless", + "break", + "class", + "local", + "using", + "while", + "else", + "from", + "then", + "when", + "with", + "and", + "for", + "not", + "do", + "if", + "in", + "or" +} +local keyword_patt +for _index_0 = 1, #keyword_words do + local word = keyword_words[_index_0] + keyword_patt = keyword_patt and (keyword_patt + P(word)) or P(word) +end +local Keyword = keyword_patt * -AlphaNum +local mark +mark = function(name, patt) + return Ct(Cc(name) * patt) +end +local pos +pos = function(patt) + return Cfn(Cp() * patt, [[return function(p, value) + if type(value) == "table" then + value[-1] = p + end + return value + end]]) +end +local assign_transform = [[ local tree = require("moonscript.parse.tree") + return function(lhs, assign) + return tree.format_assign(lhs, assign) + end]] +local sym +sym = function(chars) + return V("Space") * P(chars) +end +local op +op = function(chars) + local patt = V("Space") * C(P(chars)) + if chars:match("^%w*$") then + patt = patt * -AlphaNum + end + return patt +end +local key +key = function(chars) + return V("Space") * P(chars) * -AlphaNum +end +return { + "Root", + Root = V("White") * V("File") * V("White") * P(-1), + White = S(" \t\r\n") ^ 0, + Break = P("\r") ^ -1 * P("\n"), + Stop = V("Break") + P(-1), + Comment = P("--") * (P(1) - S("\r\n")) ^ 0 * L(V("Stop")), + Space = S(" \t") ^ 0 * V("Comment") ^ -1, + SomeSpace = S(" \t") ^ 1 * V("Comment") ^ -1, + SpaceBreak = V("Space") * V("Break"), + EmptyLine = V("SpaceBreak"), + Shebang = P("#!") * (P(1) - V("Stop")) ^ 0, + NameRaw = C(R("az", "AZ", "__") * AlphaNum ^ 0), + Name = V("Space") * -Keyword * V("NameRaw"), + Num = V("Space") * Ct(Cc("number") * C(P("0x") * R("09", "af", "AF") ^ 1 * (S("uU") ^ -1 * S("lL") ^ 2) ^ -1 + R("09") ^ 1 * (S("uU") ^ -1 * S("lL") ^ 2) + (R("09") ^ 1 * (P(".") * R("09") ^ 1) ^ -1 + P(".") * R("09") ^ 1) * (S("eE") * P("-") ^ -1 * R("09") ^ 1) ^ -1)), + SelfName = V("Space") * P("@") * (P("@") * (mark("self_class", V("NameRaw")) + Cc("self.__class")) + mark("self", V("NameRaw")) + Cc("self")), + KeyName = V("SelfName") + V("Space") * mark("key_literal", V("NameRaw")), + VarArg = V("Space") * C(P("...")), + File = V("Shebang") ^ -1 * (V("Block") + Ct(P(""))), + Block = Ct(V("Line") * (V("Break") ^ 1 * V("Line")) ^ 0), + CheckIndent = ind.check, + Line = V("CheckIndent") * V("Statement") + V("Space") * L(V("Stop")), + Statement = Cfn(pos(V("Import") + V("While") + V("With") + V("For") + V("ForEach") + V("Switch") + V("Return") + V("Local") + V("Export") + V("BreakLoop") + Cfn(Ct(V("ExpList")) * (V("Update") + V("Assign")) ^ -1, assign_transform)) * V("Space") * ((mark("if", key("if") * V("Exp") * (key("else") * V("Exp")) ^ -1 * V("Space")) + mark("unless", key("unless") * V("Exp")) + mark("comprehension", V("CompInner"))) * V("Space")) ^ -1, [[return function(stm, dec) + if dec then + return {"decorated", stm, dec} + end + return stm + end]]), + Body = V("Space") * V("Break") * V("EmptyLine") ^ 0 * V("InBlock") + Ct(V("Statement")), + Advance = ind.advance, + PushIndent = ind.push, + PreventIndent = ind.prevent, + PopIndent = ind.pop, + InBlock = V("Advance") * V("Block") * V("PopIndent"), + Local = key("local") * (mark("declare_glob", op("*") + op("^")) + mark("declare_with_shadows", Ct(V("NameList")))), + Import = mark("import", key("import") * Ct(V("ImportNameList")) * V("SpaceBreak") ^ 0 * key("from") * V("Exp")), + ImportName = sym("\\") * Ct(Cc("colon") * V("Name")) + V("Name"), + ImportNameList = V("SpaceBreak") ^ 0 * V("ImportName") * ((V("SpaceBreak") ^ 1 + sym(",") * V("SpaceBreak") ^ 0) * V("ImportName")) ^ 0, + BreakLoop = Ct(key("break") * Cc("break")) + Ct(key("continue") * Cc("continue")), + Return = mark("return", key("return") * (mark("explist", V("ExpListLow")) + C(P("")))), + WithExp = Cfn(Ct(V("ExpList")) * V("Assign") ^ -1, assign_transform), + With = mark("with", key("with") * DisableDo * V("WithExp") * PopDo * key("do") ^ -1 * V("Body")), + Switch = mark("switch", key("switch") * DisableDo * V("Exp") * PopDo * key("do") ^ -1 * V("Space") * V("Break") * V("SwitchBlock")), + SwitchBlock = V("EmptyLine") ^ 0 * V("Advance") * Ct(V("SwitchCase") * (V("Break") ^ 1 * V("SwitchCase")) ^ 0 * (V("Break") ^ 1 * V("SwitchElse")) ^ -1) * V("PopIndent"), + SwitchCase = mark("case", key("when") * Ct(V("ExpList")) * key("then") ^ -1 * V("Body")), + SwitchElse = mark("else", key("else") * V("Body")), + IfCond = Cfn(V("Exp") * V("Assign") ^ -1, [[ local tree = require("moonscript.parse.tree") + return function(lhs, assign) + return tree.format_single_assign(lhs, assign) + end]]), + IfElse = mark("else", (V("Break") * V("EmptyLine") ^ 0 * V("CheckIndent")) ^ -1 * key("else") * V("Body")), + IfElseIf = mark("elseif", (V("Break") * V("EmptyLine") ^ 0 * V("CheckIndent")) ^ -1 * key("elseif") * pos(V("IfCond")) * key("then") ^ -1 * V("Body")), + If = mark("if", key("if") * V("IfCond") * key("then") ^ -1 * V("Body") * V("IfElseIf") ^ 0 * V("IfElse") ^ -1), + Unless = mark("unless", key("unless") * V("IfCond") * key("then") ^ -1 * V("Body") * V("IfElseIf") ^ 0 * V("IfElse") ^ -1), + While = mark("while", key("while") * DisableDo * V("Exp") * PopDo * key("do") ^ -1 * V("Body")), + For = mark("for", key("for") * DisableDo * V("Name") * sym("=") * Ct(V("Exp") * sym(",") * V("Exp") * (sym(",") * V("Exp")) ^ -1) * PopDo * key("do") ^ -1 * V("Body")), + ForEach = mark("foreach", key("for") * Ct(V("AssignableNameList")) * key("in") * DisableDo * Ct(sym("*") * mark("unpack", V("Exp")) + V("ExpList")) * PopDo * key("do") ^ -1 * V("Body")), + Do = mark("do", key("do") * V("Body")), + Comprehension = mark("comprehension", sym("[") * V("Exp") * V("CompInner") * sym("]")), + TblComprehension = mark("tblcomprehension", sym("{") * Ct(V("Exp") * (sym(",") * V("Exp")) ^ -1) * V("CompInner") * sym("}")), + CompInner = Ct((V("CompForEach") + V("CompFor")) * V("CompClause") ^ 0), + CompForEach = mark("foreach", key("for") * Ct(V("AssignableNameList")) * key("in") * (sym("*") * mark("unpack", V("Exp")) + V("Exp"))), + CompFor = V("Space") * Ct(Cc("for") * P("for") * V("Name") * sym("=") * Ct(V("Exp") * sym(",") * V("Exp") * (sym(",") * V("Exp")) ^ -1)) * -AlphaNum, + CompClause = V("CompFor") + V("CompForEach") + mark("when", key("when") * V("Exp")), + Assign = mark("assign", sym("=") * (Ct(V("With") + V("If") + V("Switch")) + Ct(V("TableBlock") + V("ExpListLow")))), + Update = mark("update", V("Space") * C(P("..=") + P("+=") + P("-=") + P("*=") + P("/=") + P("%=") + P("or=") + P("and=") + P("&=") + P("|=") + P(">>=") + P("<<=")) * V("Exp")), + CharOperators = V("Space") * C(S("+-*/%^><|&")), + WordOperators = op("or") + op("and") + op("<=") + op(">=") + op("~=") + op("!=") + op("==") + op("..") + op("<<") + op(">>") + op("//"), + BinaryOperator = (V("WordOperators") + V("CharOperators")) * V("SpaceBreak") ^ 0, + Assignable = Cmt(V("Chain"), [[ local subject, pos, node = ... + local last = node[#node] + local t = type(last) == "table" and last[1] + if t == "dot" or t == "index" or t == "slice" then + return pos, node + end + return false + ]]) + V("Name") + V("SelfName"), + Exp = Cfn(V("Value") * (V("BinaryOperator") * V("Value")) ^ 0, [[return function(...) + if select("#", ...) == 1 then + return ... + end + return {"exp", ...} + end]]), + SimpleValue = V("If") + V("Unless") + V("Switch") + V("With") + V("ClassDecl") + V("ForEach") + V("For") + V("While") + CheckDo * V("Do") + mark("minus", sym("-") * -V("SomeSpace") * V("Exp")) + mark("length", sym("#") * V("Exp")) + mark("bitnot", sym("~") * V("Exp")) + mark("not", key("not") * V("Exp")) + V("TblComprehension") + V("TableLit") + V("Comprehension") + V("FunLit") + V("Num"), + ChainValue = Cfn((V("Chain") + V("Callable")) * Ct(V("InvokeArgs") ^ -1), [[ local tree = require("moonscript.parse.tree") + return function(callee, args) + return tree.join_chain(callee, args) + end]]), + Value = pos(V("SimpleValue") + mark("table", Ct(V("KeyValueList"))) + V("ChainValue") + V("String")), + SliceValue = V("Exp"), + String = V("Space") * V("DoubleString") + V("Space") * V("SingleString") + V("LuaString"), + SingleString = mark("string", C(P("'")) * C((P("\\'") + P("\\\\") + (P(1) - P("'"))) ^ 0) * P("'")), + DoubleString = mark("string", C(P('"')) * (C((V("DoubleStringInner") - P('#{')) ^ 1) + V("DoubleStringInterp")) ^ 0 * P('"')), + DoubleStringInner = P('\\"') + P("\\\\") + (P(1) - P('"')), + DoubleStringInterp = mark("interpolate", P('#{') * V("Exp") * sym("}")), + LuaString = Cfn(V("Space") * P("[") * Cp() * Cg(P("=") ^ 0, "lua_eq") * Cp() * P("[") * V("Break") ^ -1 * C((P(1) - V("LuaStringClose")) ^ 0) * V("LuaStringClose"), [[return function(eq_start, eq_end, content) + return {"string", "[" .. ("="):rep(eq_end - eq_start) .. "[", content} + end]]), + LuaStringClose = P("]") * Cmb("lua_eq") * P("]"), + Callable = pos(mark("ref", V("Name"))) + V("SelfName") + V("VarArg") + mark("parens", V("Parens")), + Parens = sym("(") * V("SpaceBreak") ^ 0 * V("Exp") * V("SpaceBreak") ^ 0 * sym(")"), + FnArgs = P("(") * V("SpaceBreak") ^ 0 * Ct(V("FnArgsExpList") ^ -1) * V("SpaceBreak") ^ 0 * sym(")") + sym("!") * -P("=") * Ct(P("")), + FnArgsExpList = V("Exp") * ((V("Break") + sym(",")) * V("White") * V("Exp")) ^ 0, + Chain = Ct(Cc("chain") * (V("Callable") + V("String") + -S(".\\")) * V("ChainItems")) + Ct(Cc("chain") * V("Space") * (V("DotChainItem") * V("ChainItems") ^ -1 + V("ColonChain"))), + ChainItems = V("ChainItem") ^ 1 * V("ColonChain") ^ -1 + V("ColonChain"), + ChainItem = V("Invoke") + V("DotChainItem") + V("Slice") + mark("index", P("[") * V("Exp")) * sym("]"), + DotChainItem = mark("dot", P(".") * V("NameRaw")), + ColonChainItem = mark("colon", P("\\") * V("NameRaw")), + ColonChain = V("ColonChainItem") * (V("Invoke") * V("ChainItems") ^ -1) ^ -1, + Slice = mark("slice", P("[") * (V("SliceValue") + Cc(1)) * sym(",") * (V("SliceValue") + Cc("")) * (sym(",") * V("SliceValue")) ^ -1 * sym("]")), + Invoke = mark("call", V("FnArgs")) + Ct(Cc("call") * Ct(V("SingleString"))) + Ct(Cc("call") * Ct(V("DoubleString"))) + L(P("[")) * Ct(Cc("call") * Ct(V("LuaString"))), + TableValue = V("KeyValue") + Ct(V("Exp")), + TableLit = mark("table", sym("{") * Ct(V("TableValueList") ^ -1 * sym(",") ^ -1 * (V("SpaceBreak") * V("TableLitLine") * (sym(",") ^ -1 * V("SpaceBreak") * V("TableLitLine")) ^ 0 * sym(",") ^ -1) ^ -1) * V("White") * sym("}")), + TableValueList = V("TableValue") * (sym(",") * V("TableValue")) ^ 0, + TableLitLine = V("PushIndent") * V("TableValueList") * V("PopIndent") + V("Space"), + TableBlockInner = Ct(V("KeyValueLine") * (V("SpaceBreak") ^ 1 * V("KeyValueLine")) ^ 0), + TableBlock = mark("table", V("SpaceBreak") ^ 1 * V("Advance") * V("TableBlockInner") * V("PopIndent")), + ClassDecl = mark("class", key("class") * -P(":") * (V("Assignable") + Cc(nil)) * (key("extends") * V("PreventIndent") * V("Exp") * V("PopIndent") + C(P(""))) ^ -1 * (V("ClassBlock") + Ct(P("")))), + ClassBlock = V("SpaceBreak") ^ 1 * V("Advance") * Ct(V("ClassLine") * (V("SpaceBreak") ^ 1 * V("ClassLine")) ^ 0) * V("PopIndent"), + ClassLine = V("CheckIndent") * ((mark("props", V("KeyValueList")) + mark("stm", V("Statement")) + mark("stm", V("Exp"))) * sym(",") ^ -1), + Export = mark("export", key("export") * (Cc("class") * V("ClassDecl") + op("*") + op("^") + Ct(V("NameList")) * (sym("=") * Ct(V("ExpListLow"))) ^ -1)), + KeyValue = Cfn(sym(":") * -V("SomeSpace") * V("Name") * Cp(), [[return function(name, p) + return { + {"key_literal", name}, + {"ref", name, [-1] = p}, + } + end]]) + Ct((V("KeyName") + sym("[") * V("Exp") * sym("]") + V("Space") * V("DoubleString") + V("Space") * V("SingleString")) * P(":") * (V("Exp") + V("TableBlock") + V("SpaceBreak") ^ 1 * V("Exp"))), + KeyValueList = V("KeyValue") * (sym(",") * V("KeyValue")) ^ 0, + KeyValueLine = V("CheckIndent") * V("KeyValueList") * sym(",") ^ -1, + FnArgsDef = sym("(") * V("White") * Ct(V("FnArgDefList") ^ -1) * (key("using") * Ct(V("NameList") + V("Space") * P("nil")) + Ct(P(""))) * V("White") * sym(")") + Ct(P("")) * Ct(P("")), + FnArgDefList = V("FnArgDef") * ((sym(",") + V("Break")) * V("White") * V("FnArgDef")) ^ 0 * ((sym(",") + V("Break")) * V("White") * Ct(V("VarArg"))) ^ 0 + Ct(V("VarArg")), + FnArgDef = Ct((V("Name") + V("SelfName") + V("TableLit")) * (sym("=") * V("Exp")) ^ -1), + FunLit = mark("fndef", V("FnArgsDef") * (sym("->") * Cc("slim") + sym("=>") * Cc("fat")) * (V("Body") + Ct(P("")))), + NameList = V("Name") * (sym(",") * V("Name")) ^ 0, + NameOrDestructure = V("Name") + V("TableLit"), + AssignableNameList = V("NameOrDestructure") * (sym(",") * V("NameOrDestructure")) ^ 0, + ExpList = V("Exp") * (sym(",") * V("Exp")) ^ 0, + ExpListLow = V("Exp") * ((sym(",") + sym(";")) * V("Exp")) ^ 0, + InvokeArgs = -P("-") * (V("ExpList") * (sym(",") * (V("TableBlock") + V("SpaceBreak") * V("Advance") * V("ArgBlock") * V("TableBlock") ^ -1) + V("TableBlock")) ^ -1 + V("TableBlock")), + ArgBlock = V("ArgLine") * (sym(",") * V("SpaceBreak") * V("ArgLine")) ^ 0 * V("PopIndent"), + ArgLine = V("CheckIndent") * V("ExpList") +} diff --git a/moonscript/parse/grammar.moon b/moonscript/parse/grammar.moon new file mode 100644 index 00000000..1c281122 --- /dev/null +++ b/moonscript/parse/grammar.moon @@ -0,0 +1,385 @@ +-- MoonScript grammar for pgen. Produces the AST consumed by the +-- moonscript compiler. +-- +-- The longer Cfn transform bodies live in moonscript/parse/tree.moon and +-- are required from the callback strings below. The callback strings are +-- Lua source: they are embedded verbatim into the generated parsers. + +pgen = require "pgen" +import P, R, S, V, C, Ct, Cc, Cp, Cg, Cmb, Cmt, Cfn, L from pgen + +ind = pgen.indenter tab_width: 4, initial: 0 + +-- `do` permission stack: the `do` expression is disabled while parsing the +-- header expression of while/with/switch/for, so the `do` in +-- `while x do ...` reads as the block keyword. 0 = disabled. +dos = pgen.indenter initial: 1 +DisableDo = dos.cpush 0 +PopDo = dos.pop +CheckDo = dos.ctop "ne", 0 + +AlphaNum = R "az", "AZ", "09", "__" + +-- Sorted longest-first: pgen's trie optimization requires longer strings +-- before their prefixes, and PEG ordered choice needs "elseif" tried +-- before "else" anyway. +keyword_words = { + "continue", "extends", + "elseif", "export", "import", "return", "switch", "unless", + "break", "class", "local", "using", "while", + "else", "from", "then", "when", "with", + "and", "for", "not", + "do", "if", "in", "or", +} + +local keyword_patt +for word in *keyword_words + keyword_patt = keyword_patt and (keyword_patt + P word) or P word + +Keyword = keyword_patt * -AlphaNum + +mark = (name, patt) -> + Ct Cc(name) * patt + +pos = (patt) -> + Cfn Cp! * patt, [[return function(p, value) + if type(value) == "table" then + value[-1] = p + end + return value + end]] + +-- Shared by Statement and WithExp; may raise error({node, msg}) for invalid +-- assignment targets, surfaced from parse() (see moonscript/parse.moon) +assign_transform = [[ + local tree = require("moonscript.parse.tree") + return function(lhs, assign) + return tree.format_assign(lhs, assign) + end]] + +sym = (chars) -> + V"Space" * P chars + +op = (chars) -> + patt = V"Space" * C P chars + if chars\match "^%w*$" + patt = patt * -AlphaNum + patt + +key = (chars) -> + V"Space" * P(chars) * -AlphaNum + +{ + "Root" + + Root: V"White" * V"File" * V"White" * P(-1) + + White: S(" \t\r\n")^0 + Break: P("\r")^-1 * P"\n" + Stop: V"Break" + P(-1) + Comment: P"--" * (P(1) - S"\r\n")^0 * L(V"Stop") + Space: S(" \t")^0 * V("Comment")^-1 + SomeSpace: S(" \t")^1 * V("Comment")^-1 + SpaceBreak: V"Space" * V"Break" + EmptyLine: V"SpaceBreak" + Shebang: P"#!" * (P(1) - V"Stop")^0 + + NameRaw: C(R("az", "AZ", "__") * AlphaNum^0) + Name: V"Space" * -Keyword * V"NameRaw" + + Num: V"Space" * Ct(Cc("number") * C( + P("0x") * R("09", "af", "AF")^1 * (S("uU")^-1 * S("lL")^2)^-1 + + R("09")^1 * (S("uU")^-1 * S("lL")^2) + + (R("09")^1 * (P(".") * R("09")^1)^-1 + P(".") * R("09")^1) * + (S("eE") * P("-")^-1 * R("09")^1)^-1 + )) + + SelfName: V"Space" * P"@" * ( + P("@") * (mark("self_class", V"NameRaw") + Cc"self.__class") + + mark("self", V"NameRaw") + Cc"self") + KeyName: V"SelfName" + V"Space" * mark("key_literal", V"NameRaw") + VarArg: V"Space" * C(P"...") + + File: V("Shebang")^-1 * (V"Block" + Ct(P"")) + Block: Ct(V"Line" * (V("Break")^1 * V"Line")^0) + CheckIndent: ind.check + Line: V"CheckIndent" * V"Statement" + V"Space" * L(V"Stop") + + Statement: Cfn( + pos( + V"Import" + V"While" + V"With" + V"For" + V"ForEach" + V"Switch" + + V"Return" + V"Local" + V"Export" + V"BreakLoop" + + Cfn(Ct(V"ExpList") * (V"Update" + V"Assign")^-1, assign_transform) + ) * V"Space" * + ((mark("if", key("if") * V"Exp" * (key("else") * V"Exp")^-1 * V"Space") + + mark("unless", key("unless") * V"Exp") + + mark("comprehension", V"CompInner")) * V"Space")^-1, + [[return function(stm, dec) + if dec then + return {"decorated", stm, dec} + end + return stm + end]]) + + Body: V"Space" * V"Break" * V("EmptyLine")^0 * V"InBlock" + Ct(V"Statement") + + Advance: ind.advance + PushIndent: ind.push + PreventIndent: ind.prevent + PopIndent: ind.pop + InBlock: V"Advance" * V"Block" * V"PopIndent" + + Local: key("local") * ( + mark("declare_glob", op("*") + op("^")) + + mark("declare_with_shadows", Ct(V"NameList"))) + + Import: mark("import", + key("import") * Ct(V"ImportNameList") * V("SpaceBreak")^0 * key("from") * V"Exp") + ImportName: sym("\\") * Ct(Cc("colon") * V"Name") + V"Name" + ImportNameList: V("SpaceBreak")^0 * V"ImportName" * + ((V("SpaceBreak")^1 + sym(",") * V("SpaceBreak")^0) * V"ImportName")^0 + + BreakLoop: Ct(key("break") * Cc"break") + Ct(key("continue") * Cc"continue") + + Return: mark("return", + key("return") * (mark("explist", V"ExpListLow") + C(P""))) + + WithExp: Cfn(Ct(V"ExpList") * V("Assign")^-1, assign_transform) + With: mark("with", + key("with") * DisableDo * V"WithExp" * PopDo * key("do")^-1 * V"Body") + + Switch: mark("switch", + key("switch") * DisableDo * V"Exp" * PopDo * key("do")^-1 * + V"Space" * V"Break" * V"SwitchBlock") + SwitchBlock: V("EmptyLine")^0 * V"Advance" * + Ct(V"SwitchCase" * (V("Break")^1 * V"SwitchCase")^0 * + (V("Break")^1 * V"SwitchElse")^-1) * V"PopIndent" + SwitchCase: mark("case", + key("when") * Ct(V"ExpList") * key("then")^-1 * V"Body") + SwitchElse: mark("else", key("else") * V"Body") + + IfCond: Cfn(V"Exp" * V("Assign")^-1, [[ + local tree = require("moonscript.parse.tree") + return function(lhs, assign) + return tree.format_single_assign(lhs, assign) + end]]) + IfElse: mark("else", + (V"Break" * V("EmptyLine")^0 * V"CheckIndent")^-1 * key("else") * V"Body") + IfElseIf: mark("elseif", + (V"Break" * V("EmptyLine")^0 * V"CheckIndent")^-1 * key("elseif") * + pos(V"IfCond") * key("then")^-1 * V"Body") + If: mark("if", + key("if") * V"IfCond" * key("then")^-1 * V"Body" * + V("IfElseIf")^0 * V("IfElse")^-1) + Unless: mark("unless", + key("unless") * V"IfCond" * key("then")^-1 * V"Body" * + V("IfElseIf")^0 * V("IfElse")^-1) + + While: mark("while", + key("while") * DisableDo * V"Exp" * PopDo * key("do")^-1 * V"Body") + + For: mark("for", + key("for") * DisableDo * V"Name" * sym("=") * + Ct(V"Exp" * sym(",") * V"Exp" * (sym(",") * V"Exp")^-1) * PopDo * + key("do")^-1 * V"Body") + ForEach: mark("foreach", + key("for") * Ct(V"AssignableNameList") * key("in") * DisableDo * + Ct(sym("*") * mark("unpack", V"Exp") + V"ExpList") * PopDo * + key("do")^-1 * V"Body") + + Do: mark("do", key("do") * V"Body") + + Comprehension: mark("comprehension", + sym("[") * V"Exp" * V"CompInner" * sym("]")) + TblComprehension: mark("tblcomprehension", + sym("{") * Ct(V"Exp" * (sym(",") * V"Exp")^-1) * V"CompInner" * sym("}")) + + CompInner: Ct((V"CompForEach" + V"CompFor") * V("CompClause")^0) + CompForEach: mark("foreach", + key("for") * Ct(V"AssignableNameList") * key("in") * + (sym("*") * mark("unpack", V"Exp") + V"Exp")) + CompFor: V"Space" * Ct(Cc("for") * P("for") * V"Name" * sym("=") * + Ct(V"Exp" * sym(",") * V"Exp" * (sym(",") * V"Exp")^-1)) * -AlphaNum + CompClause: V"CompFor" + V"CompForEach" + mark("when", key("when") * V"Exp") + + Assign: mark("assign", sym("=") * ( + Ct(V"With" + V"If" + V"Switch") + + Ct(V"TableBlock" + V"ExpListLow"))) + + Update: mark("update", + V"Space" * C( + P("..=") + P("+=") + P("-=") + P("*=") + P("/=") + P("%=") + + P("or=") + P("and=") + P("&=") + P("|=") + P(">>=") + P("<<=")) * V"Exp") + + CharOperators: V"Space" * C(S"+-*/%^><|&") + WordOperators: + op("or") + op("and") + op("<=") + op(">=") + op("~=") + op("!=") + op("==") + + op("..") + op("<<") + op(">>") + op("//") + BinaryOperator: (V"WordOperators" + V"CharOperators") * V("SpaceBreak")^0 + + Assignable: Cmt(V"Chain", [[ + local subject, pos, node = ... + local last = node[#node] + local t = type(last) == "table" and last[1] + if t == "dot" or t == "index" or t == "slice" then + return pos, node + end + return false + ]]) + V"Name" + V"SelfName" + + Exp: Cfn(V"Value" * (V"BinaryOperator" * V"Value")^0, [[return function(...) + if select("#", ...) == 1 then + return ... + end + return {"exp", ...} + end]]) + + SimpleValue: + V"If" + V"Unless" + V"Switch" + V"With" + V"ClassDecl" + + V"ForEach" + V"For" + V"While" + + CheckDo * V"Do" + + mark("minus", sym("-") * -V"SomeSpace" * V"Exp") + + mark("length", sym("#") * V"Exp") + + mark("bitnot", sym("~") * V"Exp") + + mark("not", key("not") * V"Exp") + + V"TblComprehension" + V"TableLit" + V"Comprehension" + V"FunLit" + V"Num" + + ChainValue: Cfn((V"Chain" + V"Callable") * Ct(V("InvokeArgs")^-1), [[ + local tree = require("moonscript.parse.tree") + return function(callee, args) + return tree.join_chain(callee, args) + end]]) + + Value: pos( + V"SimpleValue" + + mark("table", Ct(V"KeyValueList")) + + V"ChainValue" + V"String") + SliceValue: V"Exp" + + String: V"Space" * V"DoubleString" + V"Space" * V"SingleString" + V"LuaString" + SingleString: mark("string", + C(P"'") * C((P("\\'") + P("\\\\") + (P(1) - P"'"))^0) * P"'") + DoubleString: mark("string", + C(P'"') * + (C((V"DoubleStringInner" - P'#{')^1) + V"DoubleStringInterp")^0 * + P'"') + DoubleStringInner: P('\\"') + P("\\\\") + (P(1) - P'"') + DoubleStringInterp: mark("interpolate", P'#{' * V"Exp" * sym("}")) + + -- The lua_eq group must sit at this Cfn's own level, not nested inside + -- another transform, or LuaStringClose's Cmb cannot see it. + LuaString: Cfn( + V"Space" * P"[" * Cp! * Cg(P("=")^0, "lua_eq") * Cp! * P"[" * + V("Break")^-1 * C((P(1) - V"LuaStringClose")^0) * V"LuaStringClose", + [[return function(eq_start, eq_end, content) + return {"string", "[" .. ("="):rep(eq_end - eq_start) .. "[", content} + end]]) + LuaStringClose: P"]" * Cmb("lua_eq") * P"]" + + Callable: pos(mark("ref", V"Name")) + V"SelfName" + V"VarArg" + + mark("parens", V"Parens") + Parens: sym("(") * V("SpaceBreak")^0 * V"Exp" * V("SpaceBreak")^0 * sym(")") + + FnArgs: P("(") * V("SpaceBreak")^0 * Ct(V("FnArgsExpList")^-1) * + V("SpaceBreak")^0 * sym(")") + + sym("!") * -P("=") * Ct(P"") + FnArgsExpList: V"Exp" * ((V"Break" + sym(",")) * V"White" * V"Exp")^0 + + Chain: Ct(Cc("chain") * + (V"Callable" + V"String" + -S".\\") * V"ChainItems") + + Ct(Cc("chain") * + V"Space" * (V"DotChainItem" * V("ChainItems")^-1 + V"ColonChain")) + + ChainItems: V("ChainItem")^1 * V("ColonChain")^-1 + V"ColonChain" + ChainItem: V"Invoke" + V"DotChainItem" + V"Slice" + + mark("index", P("[") * V"Exp") * sym("]") + DotChainItem: mark("dot", P(".") * V"NameRaw") + ColonChainItem: mark("colon", P("\\") * V"NameRaw") + ColonChain: V"ColonChainItem" * (V"Invoke" * V("ChainItems")^-1)^-1 + + Slice: mark("slice", + P("[") * (V"SliceValue" + Cc(1)) * sym(",") * (V"SliceValue" + Cc("")) * + (sym(",") * V"SliceValue")^-1 * sym("]")) + + Invoke: mark("call", V"FnArgs") + + Ct(Cc("call") * Ct(V"SingleString")) + + Ct(Cc("call") * Ct(V"DoubleString")) + + L(P"[") * Ct(Cc("call") * Ct(V"LuaString")) + + TableValue: V"KeyValue" + Ct(V"Exp") + TableLit: mark("table", + sym("{") * Ct( + V("TableValueList")^-1 * sym(",")^-1 * + (V"SpaceBreak" * V"TableLitLine" * + (sym(",")^-1 * V"SpaceBreak" * V"TableLitLine")^0 * sym(",")^-1)^-1 + ) * V"White" * sym("}")) + TableValueList: V"TableValue" * (sym(",") * V"TableValue")^0 + TableLitLine: V"PushIndent" * V"TableValueList" * V"PopIndent" + V"Space" + + TableBlockInner: Ct(V"KeyValueLine" * (V("SpaceBreak")^1 * V"KeyValueLine")^0) + TableBlock: mark("table", + V("SpaceBreak")^1 * V"Advance" * V"TableBlockInner" * V"PopIndent") + + ClassDecl: mark("class", + key("class") * -P(":") * + (V"Assignable" + Cc(nil)) * + (key("extends") * V"PreventIndent" * V"Exp" * V"PopIndent" + C(P""))^-1 * + (V"ClassBlock" + Ct(P""))) + + ClassBlock: V("SpaceBreak")^1 * V"Advance" * + Ct(V"ClassLine" * (V("SpaceBreak")^1 * V"ClassLine")^0) * V"PopIndent" + ClassLine: V"CheckIndent" * ( + (mark("props", V"KeyValueList") + + mark("stm", V"Statement") + + mark("stm", V"Exp")) * sym(",")^-1) + + Export: mark("export", key("export") * ( + Cc("class") * V"ClassDecl" + + op("*") + op("^") + + Ct(V"NameList") * (sym("=") * Ct(V"ExpListLow"))^-1)) + + KeyValue: + -- {:name} shorthand expands to the key/value pair + Cfn(sym(":") * -V"SomeSpace" * V"Name" * Cp!, [[return function(name, p) + return { + {"key_literal", name}, + {"ref", name, [-1] = p}, + } + end]]) + + Ct((V"KeyName" + sym("[") * V"Exp" * sym("]") + + V"Space" * V"DoubleString" + V"Space" * V"SingleString") * + P(":") * + (V"Exp" + V"TableBlock" + V("SpaceBreak")^1 * V"Exp")) + KeyValueList: V"KeyValue" * (sym(",") * V"KeyValue")^0 + KeyValueLine: V"CheckIndent" * V"KeyValueList" * sym(",")^-1 + + FnArgsDef: sym("(") * V"White" * Ct(V("FnArgDefList")^-1) * + (key("using") * Ct(V"NameList" + V"Space" * P"nil") + Ct(P"")) * + V"White" * sym(")") + + Ct(P"") * Ct(P"") + FnArgDefList: V"FnArgDef" * + ((sym(",") + V"Break") * V"White" * V"FnArgDef")^0 * + ((sym(",") + V"Break") * V"White" * Ct(V"VarArg"))^0 + + Ct(V"VarArg") + FnArgDef: Ct((V"Name" + V"SelfName" + V"TableLit") * (sym("=") * V"Exp")^-1) + + FunLit: mark("fndef", + V"FnArgsDef" * + (sym("->") * Cc("slim") + sym("=>") * Cc("fat")) * + (V"Body" + Ct(P""))) + + NameList: V"Name" * (sym(",") * V"Name")^0 + NameOrDestructure: V"Name" + V"TableLit" + AssignableNameList: V"NameOrDestructure" * (sym(",") * V"NameOrDestructure")^0 + + ExpList: V"Exp" * (sym(",") * V"Exp")^0 + ExpListLow: V"Exp" * ((sym(",") + sym(";")) * V"Exp")^0 + + InvokeArgs: -P("-") * ( + V"ExpList" * + (sym(",") * (V"TableBlock" + V"SpaceBreak" * V"Advance" * V"ArgBlock" * V("TableBlock")^-1) + + V"TableBlock")^-1 + + V"TableBlock") + ArgBlock: V"ArgLine" * (sym(",") * V"SpaceBreak" * V"ArgLine")^0 * V"PopIndent" + ArgLine: V"CheckIndent" * V"ExpList" +} diff --git a/moonscript/parse/literals.lua b/moonscript/parse/literals.lua deleted file mode 100644 index 1ad5aeb5..00000000 --- a/moonscript/parse/literals.lua +++ /dev/null @@ -1,39 +0,0 @@ -local safe_module -safe_module = require("moonscript.util").safe_module -local S, P, R, C -do - local _obj_0 = require("lpeg") - S, P, R, C = _obj_0.S, _obj_0.P, _obj_0.R, _obj_0.C -end -local lpeg = require("lpeg") -local L = lpeg.luversion and lpeg.L or function(v) - return #v -end -local White = S(" \t\r\n") ^ 0 -local plain_space = S(" \t") ^ 0 -local Break = P("\r") ^ -1 * P("\n") -local Stop = Break + -1 -local Comment = P("--") * (1 - S("\r\n")) ^ 0 * L(Stop) -local Space = plain_space * Comment ^ -1 -local SomeSpace = S(" \t") ^ 1 * Comment ^ -1 -local SpaceBreak = Space * Break -local EmptyLine = SpaceBreak -local AlphaNum = R("az", "AZ", "09", "__") -local Name = C(R("az", "AZ", "__") * AlphaNum ^ 0) -local Num = P("0x") * R("09", "af", "AF") ^ 1 * (S("uU") ^ -1 * S("lL") ^ 2) ^ -1 + R("09") ^ 1 * (S("uU") ^ -1 * S("lL") ^ 2) + (R("09") ^ 1 * (P(".") * R("09") ^ 1) ^ -1 + P(".") * R("09") ^ 1) * (S("eE") * P("-") ^ -1 * R("09") ^ 1) ^ -1 -local Shebang = P("#!") * P(1 - Stop) ^ 0 -return safe_module("moonscript.parse.literals", { - L = L, - White = White, - Break = Break, - Stop = Stop, - Comment = Comment, - Space = Space, - SomeSpace = SomeSpace, - SpaceBreak = SpaceBreak, - EmptyLine = EmptyLine, - AlphaNum = AlphaNum, - Name = Name, - Num = Num, - Shebang = Shebang -}) diff --git a/moonscript/parse/literals.moon b/moonscript/parse/literals.moon deleted file mode 100644 index 5a4980f3..00000000 --- a/moonscript/parse/literals.moon +++ /dev/null @@ -1,38 +0,0 @@ --- non-recursive parsers -import safe_module from require "moonscript.util" -import S, P, R, C from require "lpeg" - -lpeg = require "lpeg" -L = lpeg.luversion and lpeg.L or (v) -> #v - -White = S" \t\r\n"^0 -plain_space = S" \t"^0 - -Break = P"\r"^-1 * P"\n" -Stop = Break + -1 - -Comment = P"--" * (1 - S"\r\n")^0 * L(Stop) -Space = plain_space * Comment^-1 -SomeSpace = S" \t"^1 * Comment^-1 - -SpaceBreak = Space * Break -EmptyLine = SpaceBreak - -AlphaNum = R "az", "AZ", "09", "__" - -Name = C R("az", "AZ", "__") * AlphaNum^0 - -Num = P"0x" * R("09", "af", "AF")^1 * (S"uU"^-1 * S"lL"^2)^-1 + - R"09"^1 * (S"uU"^-1 * S"lL"^2) + - ( - R"09"^1 * (P"." * R"09"^1)^-1 + - P"." * R"09"^1 - ) * (S"eE" * P"-"^-1 * R"09"^1)^-1 - -Shebang = P"#!" * P(1 - Stop)^0 - -safe_module "moonscript.parse.literals", { - :L - :White, :Break, :Stop, :Comment, :Space, :SomeSpace, :SpaceBreak, :EmptyLine, - :AlphaNum, :Name, :Num, :Shebang -} diff --git a/moonscript/parse/native.c b/moonscript/parse/native.c new file mode 100644 index 00000000..10d21986 --- /dev/null +++ b/moonscript/parse/native.c @@ -0,0 +1,22147 @@ +// Generated by pgen 0.1.0 + +#include +#include +#include +#include +#include +#include +#include +#include + +// moonscript_parse_native - generated parser + +// Maximum rule-call recursion depth before the parse is aborted with a Lua +// error (prevents C stack overflow on deeply nested input). Override with +// the max_depth compile option or -DPGEN_MAX_DEPTH=n +#ifndef PGEN_MAX_DEPTH +#define PGEN_MAX_DEPTH 5000 +#endif + +// --- Capture log --- +// Captures are recorded as log entries during matching and only materialized +// into Lua values after the whole parse succeeds. Backtracking rewinds the +// log length, so discarded speculative captures never touch the Lua runtime. +// The exception is Cmt: its callback runs mid-parse and its extra return +// values live on the Lua stack, referenced by PGEN_CAP_VALUE entries. +enum { + PGEN_CAP_STR, // start/len: slice of the input + PGEN_CAP_CONST, // aux: registry ref of an interned constant + PGEN_CAP_NIL, + PGEN_CAP_POS, // start: input position + PGEN_CAP_VALUE, // aux: absolute Lua stack index (Cmt results) + PGEN_CAP_TBL_OPEN, // Ct brackets + PGEN_CAP_TBL_CLOSE, + PGEN_CAP_GROUP_OPEN, // Cg brackets; aux: name index, start: input position + PGEN_CAP_GROUP_CLOSE, + PGEN_CAP_FN_OPEN, // Cfn brackets; aux: callback registry ref, start: pos + PGEN_CAP_FN_CLOSE +}; + +// Bracket kind tests: OPEN kinds and their CLOSE kinds are laid out in +// matching order after the scalar kinds +#define PGEN_CAP_IS_OPEN(k) \ + ((k) == PGEN_CAP_TBL_OPEN || (k) == PGEN_CAP_GROUP_OPEN || (k) == PGEN_CAP_FN_OPEN) +#define PGEN_CAP_IS_CLOSE(k) \ + ((k) == PGEN_CAP_TBL_CLOSE || (k) == PGEN_CAP_GROUP_CLOSE || (k) == PGEN_CAP_FN_CLOSE) + +typedef struct { + int kind; + int aux; + size_t start; + size_t len; +} PgenCap; + +// Single-slot memo for position-pure rules: pos is the memoized input +// position + 1 (0 = empty slot), endpos the resulting position or +// (size_t)-1 for failure +#define PGEN_MEMO_COUNT 10 +typedef struct { + size_t pos; + size_t endpos; +} PgenMemoSlot; + +#include + +// Indenter (match-time integer stack) infrastructure +#define PGEN_HAS_IND 1 +#define PGEN_IND_STACK_COUNT 2 +// Sentinel pushed by `prevent`: no measured width compares greater than it, +// so any nested `advance` fails +#define PGEN_IND_PREVENT_SENTINEL INT_MAX + +typedef struct { + int *items; + int size; + int cap; +} PgenIndStack; + +// Undo log entry for transactional stack operations. Rewinding the trail on +// backtrack reverses every push/pop performed since the choice point. +typedef struct { + unsigned char stack_id; + unsigned char op; // 0 = push, 1 = pop + int value; // for pop entries: the value that was popped +} PgenTrailEntry; + +typedef struct { + const char *input; + size_t input_len; + size_t pos; + bool success; + char error_message[256]; + const char *throw_label; // Label from T() or NULL for ordinary failure + size_t throw_pos; // Position where T() was thrown + size_t furthest_fail; // Furthest position where a match attempt failed + size_t depth; + int top; // Shadow of lua_gettop(L), exact between patterns + int stack_claimed; // Stack index secured so far via lua_checkstack + PgenCap *caps; // Capture log + size_t cap_len; + size_t cap_cap; + PgenMemoSlot memo[PGEN_MEMO_COUNT]; + lua_State *L; + PgenIndStack ind_stacks[PGEN_IND_STACK_COUNT]; + PgenTrailEntry *trail; + size_t trail_len; + size_t trail_cap; +} Parser; + +typedef struct { + size_t pos; + size_t cap_len; + int stack_size; + size_t trail_index; +} ParserPosition; + +typedef struct { + size_t pos; +} ParserInputPosition; + +// Set the Lua stack top, keeping the parser's shadow copy in sync. Any +// batched lua_checkstack claim beyond what survives GC stack shrinking is +// forfeited: capacity may shrink to twice the in-use size, but never below +// the runtime's minimum allocation (conservatively PGEN_STACK_FLOOR). +#define PGEN_SETTOP(parser, n) \ + do { \ + int pgen_newtop_ = (n); \ + lua_settop((parser)->L, pgen_newtop_); \ + (parser)->top = pgen_newtop_; \ + int pgen_keep_ = 2 * pgen_newtop_; \ + if (pgen_keep_ < PGEN_STACK_FLOOR) \ + pgen_keep_ = PGEN_STACK_FLOOR; \ + if ((parser)->stack_claimed > pgen_keep_) \ + (parser)->stack_claimed = pgen_keep_; \ + } while (0) + +#define REMEMBER_POSITION(parser, pp) \ + ParserPosition pp; \ + (pp).pos = (parser)->pos; \ + (pp).cap_len = (parser)->cap_len; \ + (pp).stack_size = (parser)->top; \ + (pp).trail_index = (parser)->trail_len; + +// Restore parser position +#define RESTORE_POSITION(parser, pp) \ + (parser)->pos = (pp).pos; \ + (parser)->cap_len = (pp).cap_len; \ + PGEN_SETTOP(parser, (pp).stack_size); \ + pgen_ind_trail_rewind(parser, (pp).trail_index); + +#define REMEMBER_INPUT_POSITION(parser, pp) \ + ParserInputPosition pp; \ + (pp).pos = (parser)->pos; + +#define RESTORE_INPUT_POSITION(parser, pp) \ + (parser)->pos = (pp).pos; + +// Records the furthest input position where a match attempt failed (only +// ever increases). Because the parser can only attempt a position it +// reached by matching everything before it, the furthest failure is the +// deepest progress into the input; parse() reports it when the overall +// parse fails without a label. +// +// Not recorded in single-character matchers (literal char, range, set): +// they fail constantly as the parser tries alternatives, and any position +// they fail at also gets tried by larger patterns (multi-char literals, +// tries, predicates, indent checks), so skipping them keeps the cost too +// small to measure without losing useful precision. +// +// Compile with -DPGEN_NO_FURTHEST to remove the tracking entirely (parse() +// then reports position 1 on ordinary failure). +#ifdef PGEN_NO_FURTHEST +#define PGEN_RECORD_FURTHEST(parser) ((void)0) +#else +#define PGEN_RECORD_FURTHEST(parser) \ + do { \ + if ((parser)->pos > (parser)->furthest_fail) \ + (parser)->furthest_fail = (parser)->pos; \ + } while (0) +#endif + +// Ensure the Lua stack can hold n more values. Captures are built on the Lua +// stack, so without this a large parse tree would overflow it (undefined +// behavior). Raises a Lua error when the stack cannot grow any further +// (LUAI_MAXCSTACK). +// +// Claims are batched so most calls are a single comparison against the +// shadow top. Batch size is limited to what survives GC stack shrinking: +// PUC Lua honors lua_checkstack claims for the frame's lifetime, but +// LuaJIT's GC may shrink capacity to twice the in-use size (never below +// its minimum allocation, conservatively PGEN_STACK_FLOOR). Claims above +// released stack space are forfeited by PGEN_SETTOP. +#define PGEN_STACK_BATCH 64 +#define PGEN_STACK_FLOOR 32 + +static void pgen_checkstack_slow(Parser *parser, int n) { + int batch = parser->top - n; // survives 2x-used shrink + int floor_batch = PGEN_STACK_FLOOR - (parser->top + n); // under shrink floor + if (floor_batch > batch) + batch = floor_batch; + if (batch > PGEN_STACK_BATCH) + batch = PGEN_STACK_BATCH; + if (batch < 0) + batch = 0; + if (lua_checkstack(parser->L, n + batch)) { + parser->stack_claimed = parser->top + n + batch; + } else if (lua_checkstack(parser->L, n)) { + // Batched request exceeded the stack limit; the exact one still fits + parser->stack_claimed = parser->top + n; + } else { + luaL_error(parser->L, "pgen: Lua stack overflow while building captures"); + } +} + +// Fast path: one comparison against the already-claimed capacity. n may be +// evaluated twice, so call sites must pass side-effect-free expressions. +#define pgen_checkstack(parser, n) \ + do { \ + if ((parser)->top + (n) > (parser)->stack_claimed) \ + pgen_checkstack_slow(parser, n); \ + } while (0) + +static void pgen_cap_grow(Parser *parser) { + size_t new_cap = parser->cap_cap * 2; + PgenCap *caps = (PgenCap *)realloc(parser->caps, new_cap * sizeof(PgenCap)); + if (!caps) { + luaL_error(parser->L, "pgen: out of memory growing capture log"); + } + parser->caps = caps; + parser->cap_cap = new_cap; +} + +// Append one log entry. A macro so the hot path (bounds check + four +// stores) inlines into every capture site; arguments may be evaluated +// twice, so call sites must pass side-effect-free expressions. +#define pgen_cap_push(parser, k, a, s, l) \ + do { \ + if ((parser)->cap_len == (parser)->cap_cap) \ + pgen_cap_grow(parser); \ + PgenCap *pgen_cap_ = &(parser)->caps[(parser)->cap_len++]; \ + pgen_cap_->kind = (k); \ + pgen_cap_->aux = (a); \ + pgen_cap_->start = (s); \ + pgen_cap_->len = (l); \ + } while (0) + +// Advance *i past one complete log item (a single entry, or a whole +// bracketed Ct/Cg range including anything nested) +static void pgen_cap_skip(Parser *parser, size_t *i) { + int kind = parser->caps[*i].kind; + (*i)++; + if (PGEN_CAP_IS_OPEN(kind)) { + int depth = 1; + while (depth > 0) { + kind = parser->caps[*i].kind; + if (PGEN_CAP_IS_OPEN(kind)) + depth++; + else if (PGEN_CAP_IS_CLOSE(kind)) + depth--; + (*i)++; + } + } +} + +// Reduce caps[base..] to only the nth capture value (group captures don't +// count), or to a single nil when there are fewer than n values +static void pgen_cap_select(Parser *parser, size_t base, int n) { + size_t i = base; + int count = 0; + while (i < parser->cap_len) { + if (parser->caps[i].kind == PGEN_CAP_GROUP_OPEN) { + pgen_cap_skip(parser, &i); + continue; + } + size_t item_start = i; + pgen_cap_skip(parser, &i); + count++; + if (count == n) { + size_t item_len = i - item_start; + memmove(&parser->caps[base], &parser->caps[item_start], item_len * sizeof(PgenCap)); + parser->cap_len = base + item_len; + return; + } + } + parser->cap_len = base; + pgen_cap_push(parser, PGEN_CAP_NIL, 0, 0, 0); +} + +// Match the text of the most recent visible "name" capture group at the +// current input position. Groups inside completed capture tables are not +// visible, mirroring the previous stack-based behavior where Ct consumed +// its inner captures. +static bool pgen_cap_match_back(Parser *parser, int name_idx) { + size_t i = parser->cap_len; + while (i > 0) { + i--; + int kind = parser->caps[i].kind; + if (PGEN_CAP_IS_CLOSE(kind)) { + size_t close = i; + int depth = 1; + while (depth > 0) { + i--; + int k2 = parser->caps[i].kind; + if (PGEN_CAP_IS_CLOSE(k2)) + depth++; + else if (PGEN_CAP_IS_OPEN(k2)) + depth--; + } + if (kind == PGEN_CAP_GROUP_CLOSE && parser->caps[i].aux == name_idx) { + const char *text; + size_t text_len; + size_t inner = i + 1; + if (inner == close) { + // group captured nothing: its value is the text it matched + text = parser->input + parser->caps[i].start; + text_len = parser->caps[close].start - parser->caps[i].start; + } else if (parser->caps[inner].kind == PGEN_CAP_STR) { + text = parser->input + parser->caps[inner].start; + text_len = parser->caps[inner].len; + } else if (parser->caps[inner].kind == PGEN_CAP_CONST) { + // interned constant: compare through the materialized value + bool matched = false; + pgen_checkstack(parser, 1); + lua_rawgeti(parser->L, LUA_REGISTRYINDEX, parser->caps[inner].aux); + if (lua_type(parser->L, -1) == LUA_TSTRING) { + size_t const_len; + const char *const_str = lua_tolstring(parser->L, -1, &const_len); + matched = parser->pos + const_len <= parser->input_len && + memcmp(parser->input + parser->pos, const_str, const_len) == 0; + if (matched) + parser->pos += const_len; + } + lua_pop(parser->L, 1); + return matched; + } else { + return false; // group holds a non-string value + } + if (parser->pos + text_len <= parser->input_len && + memcmp(parser->input + parser->pos, text, text_len) == 0) { + parser->pos += text_len; + return true; + } + return false; + } + } + } + return false; +} + +// Rewind the indenter trail to a previous length, undoing pushes and pops +static void pgen_ind_trail_rewind(Parser *parser, size_t index) { + while (parser->trail_len > index) { + parser->trail_len--; + PgenTrailEntry *e = &parser->trail[parser->trail_len]; + PgenIndStack *s = &parser->ind_stacks[e->stack_id]; + if (e->op == 0) { + // undo push + s->size--; + } else { + // undo pop: the slot is still allocated, restore the value + s->items[s->size] = e->value; + s->size++; + } + } +} + +static void pgen_ind_trail_record(Parser *parser, int stack_id, int op, int value) { + if (parser->trail_len >= parser->trail_cap) { + size_t new_cap = parser->trail_cap == 0 ? 64 : parser->trail_cap * 2; + PgenTrailEntry *trail = (PgenTrailEntry *)realloc(parser->trail, new_cap * sizeof(PgenTrailEntry)); + if (!trail) { + luaL_error(parser->L, "pgen: out of memory growing indenter trail"); + } + parser->trail = trail; + parser->trail_cap = new_cap; + } + parser->trail[parser->trail_len].stack_id = (unsigned char)stack_id; + parser->trail[parser->trail_len].op = (unsigned char)op; + parser->trail[parser->trail_len].value = value; + parser->trail_len++; +} + +static void pgen_ind_push(Parser *parser, int stack_id, int value) { + PgenIndStack *s = &parser->ind_stacks[stack_id]; + if (s->size >= s->cap) { + int new_cap = s->cap * 2; + int *items = (int *)realloc(s->items, new_cap * sizeof(int)); + if (!items) { + luaL_error(parser->L, "pgen: out of memory growing indenter stack"); + } + s->items = items; + s->cap = new_cap; + } + s->items[s->size++] = value; + pgen_ind_trail_record(parser, stack_id, 0, value); +} + +// Pop the stack; returns false if the stack is empty +static bool pgen_ind_pop(Parser *parser, int stack_id) { + PgenIndStack *s = &parser->ind_stacks[stack_id]; + if (s->size == 0) { + return false; + } + s->size--; + pgen_ind_trail_record(parser, stack_id, 1, s->items[s->size]); + return true; +} + +// Measure the indentation width of the run of space/tab characters at the +// current position (space = 1, tab = tab_width). Sets *end_pos to the first +// position past the run. +static int pgen_ind_measure(Parser *parser, size_t *end_pos, int tab_width) { + size_t p = parser->pos; + int width = 0; + while (p < parser->input_len) { + char c = parser->input[p]; + if (c == ' ') { + width += 1; + } else if (c == '\t') { + width += tab_width; + } else { + break; + } + p++; + } + *end_pos = p; + return width; +} + +#ifdef PGEN_DEBUG +static void dumpstack(lua_State *L) { + int top = lua_gettop(L); + for (int i = 1; i <= top; i++) { + printf("%d\t%s\t", i, luaL_typename(L, i)); + switch (lua_type(L, i)) { + case LUA_TNUMBER: + printf("%g\n", lua_tonumber(L, i)); + break; + case LUA_TSTRING: + printf("%s\n", lua_tostring(L, i)); + break; + case LUA_TBOOLEAN: + printf("%s\n", (lua_toboolean(L, i) ? "true" : "false")); + break; + case LUA_TNIL: + printf("%s\n", "nil"); + break; + default: + printf("%p\n", lua_topointer(L, i)); + break; + } + } +} +#endif + +// Named capture group names (GROUP entry aux = index here) +static const char *__cg_names[] = { + "lua_eq", + NULL // terminator +}; + +static int __cg_name_refs[1]; +// Interned constants (pushed once at module load) +static int __const_refs[53]; + +static void __const_init(lua_State *L) { + lua_pushlstring(L, "", 0); + __const_refs[0] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "assign", 6); + __const_refs[1] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "bitnot", 6); + __const_refs[2] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "break", 5); + __const_refs[3] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "call", 4); + __const_refs[4] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "case", 4); + __const_refs[5] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "chain", 5); + __const_refs[6] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "class", 5); + __const_refs[7] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "colon", 5); + __const_refs[8] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "comprehension", 13); + __const_refs[9] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "continue", 8); + __const_refs[10] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "declare_glob", 12); + __const_refs[11] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "declare_with_shadows", 20); + __const_refs[12] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "do", 2); + __const_refs[13] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "dot", 3); + __const_refs[14] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "else", 4); + __const_refs[15] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "elseif", 6); + __const_refs[16] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "explist", 7); + __const_refs[17] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "export", 6); + __const_refs[18] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "fat", 3); + __const_refs[19] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "fndef", 5); + __const_refs[20] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "for", 3); + __const_refs[21] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "foreach", 7); + __const_refs[22] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "if", 2); + __const_refs[23] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "import", 6); + __const_refs[24] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "index", 5); + __const_refs[25] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "interpolate", 11); + __const_refs[26] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "key_literal", 11); + __const_refs[27] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "length", 6); + __const_refs[28] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "minus", 5); + __const_refs[29] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "not", 3); + __const_refs[30] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "number", 6); + __const_refs[31] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "parens", 6); + __const_refs[32] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "props", 5); + __const_refs[33] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "ref", 3); + __const_refs[34] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "return", 6); + __const_refs[35] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "self", 4); + __const_refs[36] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "self.__class", 12); + __const_refs[37] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "self_class", 10); + __const_refs[38] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "slice", 5); + __const_refs[39] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "slim", 4); + __const_refs[40] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "stm", 3); + __const_refs[41] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "string", 6); + __const_refs[42] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "switch", 6); + __const_refs[43] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "table", 5); + __const_refs[44] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "tblcomprehension", 16); + __const_refs[45] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "unless", 6); + __const_refs[46] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "unpack", 6); + __const_refs[47] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "update", 6); + __const_refs[48] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "when", 4); + __const_refs[49] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "while", 5); + __const_refs[50] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushlstring(L, "with", 4); + __const_refs[51] = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushnumber(L, 1); + __const_refs[52] = luaL_ref(L, LUA_REGISTRYINDEX); + for (int i = 0; __cg_names[i] != NULL; i++) { + lua_pushstring(L, __cg_names[i]); + __cg_name_refs[i] = luaL_ref(L, LUA_REGISTRYINDEX); + } +} +// --- Capture log evaluation --- + +static int pgen_cap_eval(Parser *parser, size_t *i); + +// Push the single value a capture group produces: its first inner capture +// value, or the text it matched when its contents produce no values +static void pgen_cap_eval_group(Parser *parser, size_t *i) { + size_t open = *i; + pgen_cap_skip(parser, i); // *i now points past GROUP_CLOSE + size_t close = *i - 1; + + size_t j = open + 1; + while (j < close) { + int produced = pgen_cap_eval(parser, &j); + if (produced > 0) { + if (produced > 1) { + // keep only the first value + lua_pop(parser->L, produced - 1); + parser->top -= produced - 1; + } + return; + } + } + + // no values: the group's value is the text it matched + size_t start = parser->caps[open].start; + pgen_checkstack(parser, 1); + lua_pushlstring(parser->L, parser->input + start, parser->caps[close].start - start); + parser->top++; +} + +// Materialize one log item (entry or bracketed range) at *i, advancing *i +// past the item. Returns the number of Lua values pushed: always 1 except +// for transform captures, whose callbacks may return any number of values. +static int pgen_cap_eval(Parser *parser, size_t *i) { + PgenCap *cap = &parser->caps[*i]; + switch (cap->kind) { + case PGEN_CAP_STR: + pgen_checkstack(parser, 1); + lua_pushlstring(parser->L, parser->input + cap->start, cap->len); + parser->top++; + (*i)++; + return 1; + case PGEN_CAP_CONST: + pgen_checkstack(parser, 1); + lua_rawgeti(parser->L, LUA_REGISTRYINDEX, cap->aux); + parser->top++; + (*i)++; + return 1; + case PGEN_CAP_NIL: + pgen_checkstack(parser, 1); + lua_pushnil(parser->L); + parser->top++; + (*i)++; + return 1; + case PGEN_CAP_POS: + pgen_checkstack(parser, 1); + lua_pushinteger(parser->L, (lua_Integer)(cap->start + 1)); + parser->top++; + (*i)++; + return 1; + case PGEN_CAP_VALUE: + pgen_checkstack(parser, 1); + lua_pushvalue(parser->L, cap->aux); + parser->top++; + (*i)++; + return 1; + case PGEN_CAP_GROUP_OPEN: + pgen_cap_eval_group(parser, i); + return 1; + case PGEN_CAP_FN_OPEN: { + // Transform capture: inner values become arguments, the callback's + // return values become the capture values (innermost-first order falls + // out of the recursion here) + size_t open = *i; + int func_base = parser->top; + pgen_checkstack(parser, 1); + lua_rawgeti(parser->L, LUA_REGISTRYINDEX, cap->aux); + parser->top++; + + int nargs = 0; + size_t j = open + 1; + while (parser->caps[j].kind != PGEN_CAP_FN_CLOSE) { + if (parser->caps[j].kind == PGEN_CAP_GROUP_OPEN) { + // named groups are not visible as arguments (as at the top level) + pgen_cap_skip(parser, &j); + } else { + nargs += pgen_cap_eval(parser, &j); + } + } + + if (nargs == 0) { + // no inner captures: the callback receives the matched text + size_t start = parser->caps[open].start; + pgen_checkstack(parser, 1); + lua_pushlstring(parser->L, parser->input + start, parser->caps[j].start - start); + nargs = 1; + } + + // lua_call propagates errors (aborts materialization on Lua error) + lua_call(parser->L, nargs, LUA_MULTRET); + parser->top = lua_gettop(parser->L); + if (parser->stack_claimed > parser->top) + parser->stack_claimed = parser->top; + + *i = j + 1; // past FN_CLOSE + return parser->top - func_base; + } + default: { // PGEN_CAP_TBL_OPEN + // No presizing: counting items would re-walk every nested subtree at + // each nesting level, which costs more than letting the table grow + pgen_checkstack(parser, 3); + lua_createtable(parser->L, 0, 0); + parser->top++; + int table_idx = parser->top; + + size_t j = *i + 1; + int array_idx = 1; + while (parser->caps[j].kind != PGEN_CAP_TBL_CLOSE) { + if (parser->caps[j].kind == PGEN_CAP_GROUP_OPEN) { + pgen_checkstack(parser, 2); + lua_rawgeti(parser->L, LUA_REGISTRYINDEX, __cg_name_refs[parser->caps[j].aux]); + parser->top++; + pgen_cap_eval_group(parser, &j); + lua_rawset(parser->L, table_idx); + parser->top -= 2; + } else { + // rawseti pops the top value, so multi-value items assign their + // indexes in reverse + int produced = pgen_cap_eval(parser, &j); + for (int v = produced - 1; v >= 0; v--) { + lua_rawseti(parser->L, table_idx, array_idx + v); + } + array_idx += produced; + parser->top -= produced; + } + } + *i = j + 1; // past TBL_CLOSE + return 1; + } + } +} + +// Run a match-time capture: materialize the inner captures, call the +// callback with (subject, pos, ...captures), and interpret its results per +// lpeg semantics: position/true = success, false/nil = failure, extra +// return values become captures (kept on the Lua stack) +static void pgen_run_cmt(Parser *parser, int func_ref, size_t start_pos, size_t cap_base, int top_base) { + lua_State *L = parser->L; + size_t pos_after_inner = parser->pos; + int leftovers = parser->top - top_base; // nested Cmt values still on the stack + + pgen_checkstack(parser, 3); + lua_rawgeti(L, LUA_REGISTRYINDEX, func_ref); + lua_pushlstring(L, parser->input, parser->input_len); + lua_pushinteger(L, (lua_Integer)(pos_after_inner + 1)); // 1-based + parser->top += 3; + + int nargs = 2; + size_t i = cap_base; + while (i < parser->cap_len) { + if (parser->caps[i].kind == PGEN_CAP_GROUP_OPEN) { + // named groups only matter inside Ct; they aren't passed as arguments + pgen_cap_skip(parser, &i); + } else { + nargs += pgen_cap_eval(parser, &i); + } + } + parser->cap_len = cap_base; // consume the inner captures + + // lua_call propagates errors (aborts parse on Lua error) + lua_call(L, nargs, LUA_MULTRET); + parser->top = lua_gettop(L); + if (parser->stack_claimed > parser->top) + parser->stack_claimed = parser->top; + + int returns_count = parser->top - (top_base + leftovers); + + if (returns_count == 0) { + // No return value = match fails + parser->success = false; + PGEN_RECORD_FURTHEST(parser); // record at pos_after_inner, before rewind + parser->pos = start_pos; + } else { + int first = top_base + leftovers + 1; + int first_type = lua_type(L, first); + if (first_type == LUA_TNUMBER) { + // Number = new position (1-based from Lua) + lua_Integer new_pos = lua_tointeger(L, first) - 1; + // Per lpeg: must be in range [pos_after_inner, input_len] + if (new_pos >= (lua_Integer)pos_after_inner && new_pos <= (lua_Integer)parser->input_len) { + parser->pos = (size_t)new_pos; + parser->success = true; + } else { + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + parser->pos = start_pos; + } + } else if (first_type == LUA_TBOOLEAN && lua_toboolean(L, first)) { + // true = succeed without consuming (position stays at pos_after_inner) + parser->success = true; + } else { + // false, nil, or other = fail + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + parser->pos = start_pos; + } + } + + if (parser->success && returns_count > 1) { + // Drop leftover nested-Cmt slots and the first return value; the + // remaining returns stay on the stack as the new captures + for (int r = 0; r < leftovers + 1; r++) { + lua_remove(L, top_base + 1); + } + parser->top -= leftovers + 1; + if (parser->stack_claimed > parser->top) + parser->stack_claimed = parser->top; + int extras = returns_count - 1; + for (int r = 0; r < extras; r++) { + pgen_cap_push(parser, PGEN_CAP_VALUE, top_base + 1 + r, 0, 0); + } + } else { + PGEN_SETTOP(parser, top_base); + } +} +// Callback (Cmt/Cfn) infrastructure + +static const char __cmt_code_0[] = " local tree = require(\"moonscript.parse.tree\")\n return function(lhs, assign)\n return tree.format_single_assign(lhs, assign)\n end"; +static const char __cmt_code_1[] = "return function(stm, dec)\n if dec then\n return {\"decorated\", stm, dec}\n end\n return stm\n end"; +static const char __cmt_code_2[] = "return function(p, value)\n if type(value) == \"table\" then\n value[-1] = p\n end\n return value\n end"; +static const char __cmt_code_3[] = " local tree = require(\"moonscript.parse.tree\")\n return function(lhs, assign)\n return tree.format_assign(lhs, assign)\n end"; +static const char __cmt_code_4[] = "return function(name, p)\n return {\n {\"key_literal\", name},\n {\"ref\", name, [-1] = p},\n }\n end"; +static const char __cmt_code_5[] = " local tree = require(\"moonscript.parse.tree\")\n return function(callee, args)\n return tree.join_chain(callee, args)\n end"; +static const char __cmt_code_6[] = "return function(...)\n if select(\"#\", ...) == 1 then\n return ...\n end\n return {\"exp\", ...}\n end"; +static const char __cmt_code_7[] = "return function(eq_start, eq_end, content)\n return {\"string\", \"[\" .. (\"=\"):rep(eq_end - eq_start) .. \"[\", content}\n end"; +static const char __cmt_code_8[] = " local subject, pos, node = ...\n local last = node[#node]\n local t = type(last) == \"table\" and last[1]\n if t == \"dot\" or t == \"index\" or t == \"slice\" then\n return pos, node\n end\n return false\n "; + +static int __cmt_refs[9]; + +// Initialize callbacks by loading their Lua code +static void __cmt_init(lua_State *L) { + if (luaL_loadstring(L, __cmt_code_0) != 0) { + luaL_error(L, "Failed to load Cfn callback 0: %s", lua_tostring(L, -1)); + } + if (lua_pcall(L, 0, 1, 0) != 0) { + luaL_error(L, "Failed to run Cfn chunk 0: %s", lua_tostring(L, -1)); + } + if (!lua_isfunction(L, -1)) { + luaL_error(L, "Cfn chunk 0 did not return a function"); + } + __cmt_refs[0] = luaL_ref(L, LUA_REGISTRYINDEX); + if (luaL_loadstring(L, __cmt_code_1) != 0) { + luaL_error(L, "Failed to load Cfn callback 1: %s", lua_tostring(L, -1)); + } + if (lua_pcall(L, 0, 1, 0) != 0) { + luaL_error(L, "Failed to run Cfn chunk 1: %s", lua_tostring(L, -1)); + } + if (!lua_isfunction(L, -1)) { + luaL_error(L, "Cfn chunk 1 did not return a function"); + } + __cmt_refs[1] = luaL_ref(L, LUA_REGISTRYINDEX); + if (luaL_loadstring(L, __cmt_code_2) != 0) { + luaL_error(L, "Failed to load Cfn callback 2: %s", lua_tostring(L, -1)); + } + if (lua_pcall(L, 0, 1, 0) != 0) { + luaL_error(L, "Failed to run Cfn chunk 2: %s", lua_tostring(L, -1)); + } + if (!lua_isfunction(L, -1)) { + luaL_error(L, "Cfn chunk 2 did not return a function"); + } + __cmt_refs[2] = luaL_ref(L, LUA_REGISTRYINDEX); + if (luaL_loadstring(L, __cmt_code_3) != 0) { + luaL_error(L, "Failed to load Cfn callback 3: %s", lua_tostring(L, -1)); + } + if (lua_pcall(L, 0, 1, 0) != 0) { + luaL_error(L, "Failed to run Cfn chunk 3: %s", lua_tostring(L, -1)); + } + if (!lua_isfunction(L, -1)) { + luaL_error(L, "Cfn chunk 3 did not return a function"); + } + __cmt_refs[3] = luaL_ref(L, LUA_REGISTRYINDEX); + if (luaL_loadstring(L, __cmt_code_4) != 0) { + luaL_error(L, "Failed to load Cfn callback 4: %s", lua_tostring(L, -1)); + } + if (lua_pcall(L, 0, 1, 0) != 0) { + luaL_error(L, "Failed to run Cfn chunk 4: %s", lua_tostring(L, -1)); + } + if (!lua_isfunction(L, -1)) { + luaL_error(L, "Cfn chunk 4 did not return a function"); + } + __cmt_refs[4] = luaL_ref(L, LUA_REGISTRYINDEX); + if (luaL_loadstring(L, __cmt_code_5) != 0) { + luaL_error(L, "Failed to load Cfn callback 5: %s", lua_tostring(L, -1)); + } + if (lua_pcall(L, 0, 1, 0) != 0) { + luaL_error(L, "Failed to run Cfn chunk 5: %s", lua_tostring(L, -1)); + } + if (!lua_isfunction(L, -1)) { + luaL_error(L, "Cfn chunk 5 did not return a function"); + } + __cmt_refs[5] = luaL_ref(L, LUA_REGISTRYINDEX); + if (luaL_loadstring(L, __cmt_code_6) != 0) { + luaL_error(L, "Failed to load Cfn callback 6: %s", lua_tostring(L, -1)); + } + if (lua_pcall(L, 0, 1, 0) != 0) { + luaL_error(L, "Failed to run Cfn chunk 6: %s", lua_tostring(L, -1)); + } + if (!lua_isfunction(L, -1)) { + luaL_error(L, "Cfn chunk 6 did not return a function"); + } + __cmt_refs[6] = luaL_ref(L, LUA_REGISTRYINDEX); + if (luaL_loadstring(L, __cmt_code_7) != 0) { + luaL_error(L, "Failed to load Cfn callback 7: %s", lua_tostring(L, -1)); + } + if (lua_pcall(L, 0, 1, 0) != 0) { + luaL_error(L, "Failed to run Cfn chunk 7: %s", lua_tostring(L, -1)); + } + if (!lua_isfunction(L, -1)) { + luaL_error(L, "Cfn chunk 7 did not return a function"); + } + __cmt_refs[7] = luaL_ref(L, LUA_REGISTRYINDEX); + if (luaL_loadstring(L, __cmt_code_8) != 0) { + luaL_error(L, "Failed to load Cmt callback 8: %s", lua_tostring(L, -1)); + } + __cmt_refs[8] = luaL_ref(L, LUA_REGISTRYINDEX); +} + +// Forward declarations +static bool parse_Root(Parser *parser); +static bool parse_Advance(Parser *parser); +static bool parse_ArgBlock(Parser *parser); +static bool parse_ArgLine(Parser *parser); +static bool parse_Assign(Parser *parser); +static bool parse_Assignable(Parser *parser); +static bool parse_AssignableNameList(Parser *parser); +static bool parse_BinaryOperator(Parser *parser); +static bool parse_Block(Parser *parser); +static bool parse_Body(Parser *parser); +static bool parse_Break(Parser *parser); +static bool parse_BreakLoop(Parser *parser); +static bool parse_Callable(Parser *parser); +static bool parse_Chain(Parser *parser); +static bool parse_ChainItem(Parser *parser); +static bool parse_ChainItems(Parser *parser); +static bool parse_ChainValue(Parser *parser); +static bool parse_CharOperators(Parser *parser); +static bool parse_CheckIndent(Parser *parser); +static bool parse_ClassBlock(Parser *parser); +static bool parse_ClassDecl(Parser *parser); +static bool parse_ClassLine(Parser *parser); +static bool parse_ColonChain(Parser *parser); +static bool parse_ColonChainItem(Parser *parser); +static bool parse_Comment(Parser *parser); +static bool parse_CompClause(Parser *parser); +static bool parse_CompFor(Parser *parser); +static bool parse_CompForEach(Parser *parser); +static bool parse_CompInner(Parser *parser); +static bool parse_Comprehension(Parser *parser); +static bool parse_Do(Parser *parser); +static bool parse_DotChainItem(Parser *parser); +static bool parse_DoubleString(Parser *parser); +static bool parse_DoubleStringInner(Parser *parser); +static bool parse_DoubleStringInterp(Parser *parser); +static bool parse_EmptyLine(Parser *parser); +static bool parse_Exp(Parser *parser); +static bool parse_ExpList(Parser *parser); +static bool parse_ExpListLow(Parser *parser); +static bool parse_Export(Parser *parser); +static bool parse_File(Parser *parser); +static bool parse_FnArgDef(Parser *parser); +static bool parse_FnArgDefList(Parser *parser); +static bool parse_FnArgs(Parser *parser); +static bool parse_FnArgsDef(Parser *parser); +static bool parse_FnArgsExpList(Parser *parser); +static bool parse_For(Parser *parser); +static bool parse_ForEach(Parser *parser); +static bool parse_FunLit(Parser *parser); +static bool parse_If(Parser *parser); +static bool parse_IfCond(Parser *parser); +static bool parse_IfElse(Parser *parser); +static bool parse_IfElseIf(Parser *parser); +static bool parse_Import(Parser *parser); +static bool parse_ImportName(Parser *parser); +static bool parse_ImportNameList(Parser *parser); +static bool parse_InBlock(Parser *parser); +static bool parse_Invoke(Parser *parser); +static bool parse_InvokeArgs(Parser *parser); +static bool parse_KeyName(Parser *parser); +static bool parse_KeyValue(Parser *parser); +static bool parse_KeyValueLine(Parser *parser); +static bool parse_KeyValueList(Parser *parser); +static bool parse_Line(Parser *parser); +static bool parse_Local(Parser *parser); +static bool parse_LuaString(Parser *parser); +static bool parse_LuaStringClose(Parser *parser); +static bool parse_Name(Parser *parser); +static bool parse_NameList(Parser *parser); +static bool parse_NameOrDestructure(Parser *parser); +static bool parse_NameRaw(Parser *parser); +static bool parse_Num(Parser *parser); +static bool parse_Parens(Parser *parser); +static bool parse_PopIndent(Parser *parser); +static bool parse_PreventIndent(Parser *parser); +static bool parse_PushIndent(Parser *parser); +static bool parse_Return(Parser *parser); +static bool parse_SelfName(Parser *parser); +static bool parse_Shebang(Parser *parser); +static bool parse_SimpleValue(Parser *parser); +static bool parse_SingleString(Parser *parser); +static bool parse_Slice(Parser *parser); +static bool parse_SliceValue(Parser *parser); +static bool parse_SomeSpace(Parser *parser); +static bool parse_Space(Parser *parser); +static bool parse_SpaceBreak(Parser *parser); +static bool parse_Statement(Parser *parser); +static bool parse_Stop(Parser *parser); +static bool parse_String(Parser *parser); +static bool parse_Switch(Parser *parser); +static bool parse_SwitchBlock(Parser *parser); +static bool parse_SwitchCase(Parser *parser); +static bool parse_SwitchElse(Parser *parser); +static bool parse_TableBlock(Parser *parser); +static bool parse_TableBlockInner(Parser *parser); +static bool parse_TableLit(Parser *parser); +static bool parse_TableLitLine(Parser *parser); +static bool parse_TableValue(Parser *parser); +static bool parse_TableValueList(Parser *parser); +static bool parse_TblComprehension(Parser *parser); +static bool parse_Unless(Parser *parser); +static bool parse_Update(Parser *parser); +static bool parse_Value(Parser *parser); +static bool parse_VarArg(Parser *parser); +static bool parse_While(Parser *parser); +static bool parse_White(Parser *parser); +static bool parse_With(Parser *parser); +static bool parse_WithExp(Parser *parser); +static bool parse_WordOperators(Parser *parser); + +// Rule functions +static bool parse_Root(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "Root", start); +#endif + + { // Sequence with 4 patterns + REMEMBER_POSITION(parser, pos); + + parse_White(parser); + if (parser->success) { + parse_File(parser); + if (parser->success) { + parse_White(parser); + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match any 1 characters + if (parser->pos + 1 <= parser->input_len) { + parser->pos += 1; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected at least 1 more characters at position %zu", parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "Root", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "Root", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_Advance(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "Advance", start); +#endif + + { // Indenter advance (stack 0): push width if deeper than top, consume nothing + size_t ind_end; + int ind_width = pgen_ind_measure(parser, &ind_end, 4); + (void)ind_end; + PgenIndStack *ind_s = &parser->ind_stacks[0]; + if (ind_s->size > 0 && ind_width > ind_s->items[ind_s->size - 1]) { + pgen_ind_push(parser, 0, ind_width); + } else { + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Indent width %d does not advance current level at position %zu", ind_width, parser->pos); +#endif + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "Advance", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "Advance", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_ArgBlock(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "ArgBlock", start); +#endif + + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + parse_ArgLine(parser); + if (parser->success) { + { // Zero or more repetitions + while (true) { + { // Sequence with 4 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match single character "," + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 44) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "," + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + parse_SpaceBreak(parser); + if (parser->success) { + parse_ArgLine(parser); + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + if (!parser->success) { + break; + } + } + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + } + if (parser->success) { + parse_PopIndent(parser); + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "ArgBlock", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "ArgBlock", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_ArgLine(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "ArgLine", start); +#endif + + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_CheckIndent(parser); + if (parser->success) { + parse_ExpList(parser); + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "ArgLine", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "ArgLine", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_Assign(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "Assign", start); +#endif + + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 4 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[1], 0, 0); // "assign" + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match single character "=" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 61) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "=" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + { // Choice + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Choice + { // Choice + parse_With(parser); + + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_If(parser); + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_Switch(parser); + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Choice + parse_TableBlock(parser); + + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_ExpListLow(parser); + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "Assign", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "Assign", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_Assignable(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "Assignable", start); +#endif + + { // Choice + { // Choice + { // Match-time capture (Cmt id=8) + size_t cmt_cap_base = parser->cap_len; + int cmt_top_base = parser->top; + size_t cmt_start_pos = parser->pos; +#ifdef PGEN_HAS_IND + size_t cmt_trail_index = parser->trail_len; +#endif + + parse_Chain(parser); + + if (parser->success) { + pgen_run_cmt(parser, __cmt_refs[8], cmt_start_pos, cmt_cap_base, cmt_top_base); + +#ifdef PGEN_HAS_IND + // Callback rejected the match: undo indenter operations performed by the + // inner pattern (an inner failure rewinds itself) + if (!parser->success) { + pgen_ind_trail_rewind(parser, cmt_trail_index); + } +#endif + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_Name(parser); + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_SelfName(parser); + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "Assignable", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "Assignable", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_AssignableNameList(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "AssignableNameList", start); +#endif + + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_NameOrDestructure(parser); + if (parser->success) { + { // Zero or more repetitions + while (true) { + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match single character "," + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 44) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "," + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + parse_NameOrDestructure(parser); + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + if (!parser->success) { + break; + } + } + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "AssignableNameList", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "AssignableNameList", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_BinaryOperator(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "BinaryOperator", start); +#endif + + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Choice + parse_WordOperators(parser); + + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_CharOperators(parser); + } + } + if (parser->success) { + { // Zero or more repetitions + while (true) { + parse_SpaceBreak(parser); + if (!parser->success) { + break; + } + } + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "BinaryOperator", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "BinaryOperator", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_Block(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "Block", start); +#endif + + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_Line(parser); + if (parser->success) { + { // Zero or more repetitions + while (true) { + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // At least 1 repetitions + REMEMBER_INPUT_POSITION(parser, pos); + size_t rep_count = 0; + + while (true) { + parse_Break(parser); + + if (!parser->success) { + break; + } + + rep_count += 1; + } + + // Don't recover if labeled failure was thrown + if (parser->throw_label) { + // Keep failure state, propagate labeled failure + } else if (rep_count >= 1) { + parser->success = true; + } else { + RESTORE_INPUT_POSITION(parser, pos); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected 1 repetitions at position %zu", parser->pos); +#endif + } + } + if (parser->success) { + parse_Line(parser); + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + if (!parser->success) { + break; + } + } + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "Block", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "Block", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_Body(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "Body", start); +#endif + + { // Choice + { // Sequence with 4 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + parse_Break(parser); + if (parser->success) { + { // Zero or more repetitions + while (true) { + parse_EmptyLine(parser); + if (!parser->success) { + break; + } + } + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + } + if (parser->success) { + parse_InBlock(parser); + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + parse_Statement(parser); + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "Body", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "Body", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_Break(Parser *parser) { + size_t start = parser->pos; + // Position-pure rule (no captures, labels, or other state): a + // single-slot memo short-circuits the repeated calls that backtracking + // alternatives make at the same position + if (parser->memo[0].pos == start + 1) { + if (parser->memo[0].endpos == (size_t)-1) { + parser->success = false; + return false; + } + parser->pos = parser->memo[0].endpos; + parser->success = true; + return true; + } + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "Break", start); +#endif + + { // Sequence with 2 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + { // Match single character "\r" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 13) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "\\r" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + if (parser->success) { + { // Match single character "\n" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 10) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "\\n" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "Break", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "Break", parser->pos); + } +#endif + parser->memo[0].pos = start + 1; + parser->memo[0].endpos = parser->success ? parser->pos : (size_t)-1; + + parser->depth -= 1; + return parser->success; +} + +static bool parse_BreakLoop(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "BreakLoop", start); +#endif + + { // Choice + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 4 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match literal "break" + if (parser->pos + 5 <= parser->input_len && + memcmp(parser->input + parser->pos, "break", 5) == 0) { + parser->pos += 5; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "break" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (parser->success) { + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[3], 0, 0); // "break" + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 4 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match literal "continue" + if (parser->pos + 8 <= parser->input_len && + memcmp(parser->input + parser->pos, "continue", 8) == 0) { + parser->pos += 8; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "continue" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (parser->success) { + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[10], 0, 0); // "continue" + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "BreakLoop", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "BreakLoop", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_Callable(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "Callable", start); +#endif + + { // FIRST-byte dispatched ordered choice + unsigned long long pgen_dispatch_mask; + if (parser->pos < parser->input_len) { + switch ((unsigned char)parser->input[parser->pos]) { + case 64: + pgen_dispatch_mask = 0x0000000000000003ULL; + break; + case 46: + pgen_dispatch_mask = 0x0000000000000005ULL; + break; + case 40: + pgen_dispatch_mask = 0x0000000000000009ULL; + break; + case 9: + case 32: + case 45: + pgen_dispatch_mask = 0x000000000000000fULL; + break; + default: + pgen_dispatch_mask = 0x0000000000000001ULL; + break; + } + } else { + pgen_dispatch_mask = 0x0000000000000001ULL; + } + + parser->success = false; + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 0))) { + parser->success = true; + { // Transform Capture (Cfn id=2) + size_t fn_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_FN_OPEN, __cmt_refs[2], parser->pos, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Position Capture + pgen_cap_push(parser, PGEN_CAP_POS, 0, parser->pos, 0); + } + if (parser->success) { + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[34], 0, 0); // "ref" + } + if (parser->success) { + parse_Name(parser); + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_FN_CLOSE, 0, parser->pos, 0); + } else { + parser->cap_len = fn_cap_start; + } + } + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 1))) { + if ((pgen_dispatch_mask & 0x0000000000000001ULL) != 0x0000000000000001ULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + parse_SelfName(parser); + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 2))) { + if ((pgen_dispatch_mask & 0x0000000000000003ULL) != 0x0000000000000003ULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + parse_VarArg(parser); + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 3))) { + if ((pgen_dispatch_mask & 0x0000000000000007ULL) != 0x0000000000000007ULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[32], 0, 0); // "parens" + } + if (parser->success) { + parse_Parens(parser); + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + if (!parser->success && !parser->throw_label) { + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + if (pgen_dispatch_mask != 0x000000000000000fULL) { + // Some alternatives were skipped: replay the whole choice in original + // order so error_message reports the same failure the undispatched + // parser would. Every alternative fails, so this only affects error + // state. + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Transform Capture (Cfn id=2) + size_t fn_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_FN_OPEN, __cmt_refs[2], parser->pos, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Position Capture + pgen_cap_push(parser, PGEN_CAP_POS, 0, parser->pos, 0); + } + if (parser->success) { + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[34], 0, 0); // "ref" + } + if (parser->success) { + parse_Name(parser); + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_FN_CLOSE, 0, parser->pos, 0); + } else { + parser->cap_len = fn_cap_start; + } + } + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_SelfName(parser); + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_VarArg(parser); + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[32], 0, 0); // "parens" + } + if (parser->success) { + parse_Parens(parser); + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + } +#endif + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "Callable", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "Callable", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_Chain(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "Chain", start); +#endif + + { // Choice + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[6], 0, 0); // "chain" + } + if (parser->success) { + { // Choice + { // Choice + parse_Callable(parser); + + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_String(parser); + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character set ".\\" + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 46: /* "." */ + case 92: /* "\\" */ + parser->pos++; + break; + default: +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected one of " + "\".\\\\\"" + " at position %zu", + parser->pos); +#endif + parser->success = false; + } + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected one of " + "\".\\\\\"" + " at position %zu but reached end of input", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + } + } + if (parser->success) { + parse_ChainItems(parser); + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[6], 0, 0); // "chain" + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Choice + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_DotChainItem(parser); + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + parse_ChainItems(parser); + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_ColonChain(parser); + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "Chain", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "Chain", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_ChainItem(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "ChainItem", start); +#endif + + { // FIRST-byte dispatched ordered choice + unsigned long long pgen_dispatch_mask; + if (parser->pos < parser->input_len) { + switch ((unsigned char)parser->input[parser->pos]) { + case 46: + pgen_dispatch_mask = 0x0000000000000003ULL; + break; + case 91: + pgen_dispatch_mask = 0x000000000000000dULL; + break; + default: + pgen_dispatch_mask = 0x0000000000000001ULL; + break; + } + } else { + pgen_dispatch_mask = 0x0000000000000001ULL; + } + + parser->success = false; + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 0))) { + parser->success = true; + parse_Invoke(parser); + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 1))) { + if ((pgen_dispatch_mask & 0x0000000000000001ULL) != 0x0000000000000001ULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + parse_DotChainItem(parser); + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 2))) { + if ((pgen_dispatch_mask & 0x0000000000000003ULL) != 0x0000000000000003ULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + parse_Slice(parser); + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 3))) { + if ((pgen_dispatch_mask & 0x0000000000000007ULL) != 0x0000000000000007ULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[25], 0, 0); // "index" + } + if (parser->success) { + { // Match single character "[" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 91) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "[" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + parse_Exp(parser); + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match single character "]" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 93) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "]" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + if (!parser->success && !parser->throw_label) { + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + if (pgen_dispatch_mask != 0x000000000000000fULL) { + // Some alternatives were skipped: replay the whole choice in original + // order so error_message reports the same failure the undispatched + // parser would. Every alternative fails, so this only affects error + // state. + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_Invoke(parser); + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_DotChainItem(parser); + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_Slice(parser); + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[25], 0, 0); // "index" + } + if (parser->success) { + { // Match single character "[" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 91) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "[" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + parse_Exp(parser); + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match single character "]" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 93) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "]" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + } +#endif + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "ChainItem", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "ChainItem", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_ChainItems(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "ChainItems", start); +#endif + + { // Choice + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // At least 1 repetitions + REMEMBER_POSITION(parser, pos); + size_t rep_count = 0; + + while (true) { + parse_ChainItem(parser); + + if (!parser->success) { + break; + } + + rep_count += 1; + } + + // Don't recover if labeled failure was thrown + if (parser->throw_label) { + // Keep failure state, propagate labeled failure + } else if (rep_count >= 1) { + parser->success = true; + } else { + RESTORE_POSITION(parser, pos); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected 1 repetitions at position %zu", parser->pos); +#endif + } + } + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + parse_ColonChain(parser); + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_ColonChain(parser); + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "ChainItems", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "ChainItems", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_ChainValue(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "ChainValue", start); +#endif + + { // Transform Capture (Cfn id=5) + size_t fn_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_FN_OPEN, __cmt_refs[5], parser->pos, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Choice + parse_Chain(parser); + + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_Callable(parser); + } + } + if (parser->success) { + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + parse_InvokeArgs(parser); + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_FN_CLOSE, 0, parser->pos, 0); + } else { + parser->cap_len = fn_cap_start; + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "ChainValue", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "ChainValue", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_CharOperators(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "CharOperators", start); +#endif + + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Capture + size_t start_pos = parser->pos; + { // Match character set "+-*\/%^><|&" + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 43: /* "+" */ + case 45: /* "-" */ + case 42: /* "*" */ + case 47: /* "/" */ + case 37: /* "%" */ + case 94: /* "^" */ + case 62: /* ">" */ + case 60: /* "<" */ + case 124: /* "|" */ + case 38: /* "&" */ + parser->pos++; + break; + default: +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected one of " + "\"+-*/%^><|&\"" + " at position %zu", + parser->pos); +#endif + parser->success = false; + } + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected one of " + "\"+-*/%^><|&\"" + " at position %zu but reached end of input", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_STR, 0, start_pos, parser->pos - start_pos); + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "CharOperators", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "CharOperators", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_CheckIndent(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "CheckIndent", start); +#endif + + { // Indenter check (stack 0): consume whitespace, width must equal top + size_t ind_end; + int ind_width = pgen_ind_measure(parser, &ind_end, 4); + PgenIndStack *ind_s = &parser->ind_stacks[0]; + if (ind_s->size > 0 && ind_s->items[ind_s->size - 1] == ind_width) { + parser->pos = ind_end; + } else { + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Indent width %d does not match current level at position %zu", ind_width, parser->pos); +#endif + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "CheckIndent", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "CheckIndent", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_ClassBlock(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "ClassBlock", start); +#endif + + { // Sequence with 4 patterns + REMEMBER_POSITION(parser, pos); + + { // At least 1 repetitions + REMEMBER_INPUT_POSITION(parser, pos); + size_t rep_count = 0; + + while (true) { + parse_SpaceBreak(parser); + + if (!parser->success) { + break; + } + + rep_count += 1; + } + + // Don't recover if labeled failure was thrown + if (parser->throw_label) { + // Keep failure state, propagate labeled failure + } else if (rep_count >= 1) { + parser->success = true; + } else { + RESTORE_INPUT_POSITION(parser, pos); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected 1 repetitions at position %zu", parser->pos); +#endif + } + } + if (parser->success) { + parse_Advance(parser); + if (parser->success) { + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_ClassLine(parser); + if (parser->success) { + { // Zero or more repetitions + while (true) { + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // At least 1 repetitions + REMEMBER_INPUT_POSITION(parser, pos); + size_t rep_count = 0; + + while (true) { + parse_SpaceBreak(parser); + + if (!parser->success) { + break; + } + + rep_count += 1; + } + + // Don't recover if labeled failure was thrown + if (parser->throw_label) { + // Keep failure state, propagate labeled failure + } else if (rep_count >= 1) { + parser->success = true; + } else { + RESTORE_INPUT_POSITION(parser, pos); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected 1 repetitions at position %zu", parser->pos); +#endif + } + } + if (parser->success) { + parse_ClassLine(parser); + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + if (!parser->success) { + break; + } + } + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + if (parser->success) { + parse_PopIndent(parser); + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "ClassBlock", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "ClassBlock", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_ClassDecl(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "ClassDecl", start); +#endif + + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 8 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[7], 0, 0); // "class" + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match literal "class" + if (parser->pos + 5 <= parser->input_len && + memcmp(parser->input + parser->pos, "class", 5) == 0) { + parser->pos += 5; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "class" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match single character ":" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 58) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + ":" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (parser->success) { + { // Choice + parse_Assignable(parser); + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_NIL, 0, 0, 0); + } + } + } + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + { // Choice + { // Sequence with 6 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match literal "extends" + if (parser->pos + 7 <= parser->input_len && + memcmp(parser->input + parser->pos, "extends", 7) == 0) { + parser->pos += 7; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "extends" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (parser->success) { + parse_PreventIndent(parser); + if (parser->success) { + parse_Exp(parser); + if (parser->success) { + parse_PopIndent(parser); + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Capture + size_t start_pos = parser->pos; + { // Match literal "" + if (parser->pos + 0 <= parser->input_len && + memcmp(parser->input + parser->pos, "", 0) == 0) { + parser->pos += 0; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_STR, 0, start_pos, parser->pos - start_pos); + } + } + } + } + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + if (parser->success) { + { // Choice + parse_ClassBlock(parser); + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Match literal "" + if (parser->pos + 0 <= parser->input_len && + memcmp(parser->input + parser->pos, "", 0) == 0) { + parser->pos += 0; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + } + } + } + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "ClassDecl", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "ClassDecl", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_ClassLine(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "ClassLine", start); +#endif + + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + parse_CheckIndent(parser); + if (parser->success) { + { // Choice + { // Choice + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[33], 0, 0); // "props" + } + if (parser->success) { + parse_KeyValueList(parser); + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[41], 0, 0); // "stm" + } + if (parser->success) { + parse_Statement(parser); + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[41], 0, 0); // "stm" + } + if (parser->success) { + parse_Exp(parser); + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + } + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + { // Sequence with 2 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match single character "," + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 44) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "," + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "ClassLine", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "ClassLine", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_ColonChain(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "ColonChain", start); +#endif + + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_ColonChainItem(parser); + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_Invoke(parser); + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + parse_ChainItems(parser); + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "ColonChain", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "ColonChain", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_ColonChainItem(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "ColonChainItem", start); +#endif + + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[8], 0, 0); // "colon" + } + if (parser->success) { + { // Match single character "\\" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 92) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "\\\\" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + parse_NameRaw(parser); + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "ColonChainItem", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "ColonChainItem", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_Comment(Parser *parser) { + size_t start = parser->pos; + // Position-pure rule (no captures, labels, or other state): a + // single-slot memo short-circuits the repeated calls that backtracking + // alternatives make at the same position + if (parser->memo[1].pos == start + 1) { + if (parser->memo[1].endpos == (size_t)-1) { + parser->success = false; + return false; + } + parser->pos = parser->memo[1].endpos; + parser->success = true; + return true; + } + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "Comment", start); +#endif + + { // Sequence with 3 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match literal "--" + if (parser->pos + 2 <= parser->input_len && + memcmp(parser->input + parser->pos, "--", 2) == 0) { + parser->pos += 2; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "--" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // Zero or more repetitions + while (true) { + { // Sequence with 2 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character set "\r\n" + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 13: /* "\r" */ + case 10: /* "\n" */ + parser->pos++; + break; + default: +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected one of " + "\"\\r\\n\"" + " at position %zu", + parser->pos); +#endif + parser->success = false; + } + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected one of " + "\"\\r\\n\"" + " at position %zu but reached end of input", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (parser->success) { + { // Match any 1 characters + if (parser->pos + 1 <= parser->input_len) { + parser->pos += 1; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected at least 1 more characters at position %zu", parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + if (!parser->success) { + break; + } + } + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + } + if (parser->success) { + { // Lookahead (match without consuming input) + REMEMBER_INPUT_POSITION(parser, pos); + + parse_Stop(parser); + + if (parser->success) { + // Pattern matched, but we don't consume any input + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "Comment", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "Comment", parser->pos); + } +#endif + parser->memo[1].pos = start + 1; + parser->memo[1].endpos = parser->success ? parser->pos : (size_t)-1; + + parser->depth -= 1; + return parser->success; +} + +static bool parse_CompClause(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "CompClause", start); +#endif + + { // Choice + { // Choice + parse_CompFor(parser); + + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_CompForEach(parser); + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 5 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[49], 0, 0); // "when" + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match literal "when" + if (parser->pos + 4 <= parser->input_len && + memcmp(parser->input + parser->pos, "when", 4) == 0) { + parser->pos += 4; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "when" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (parser->success) { + parse_Exp(parser); + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "CompClause", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "CompClause", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_CompFor(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "CompFor", start); +#endif + + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 6 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[21], 0, 0); // "for" + } + if (parser->success) { + { // Match literal "for" + if (parser->pos + 3 <= parser->input_len && + memcmp(parser->input + parser->pos, "for", 3) == 0) { + parser->pos += 3; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "for" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + parse_Name(parser); + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match single character "=" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 61) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "=" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 5 patterns + REMEMBER_POSITION(parser, pos); + + parse_Exp(parser); + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match single character "," + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 44) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "," + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + parse_Exp(parser); + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match single character "," + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 44) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "," + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + parse_Exp(parser); + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "CompFor", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "CompFor", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_CompForEach(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "CompForEach", start); +#endif + + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 9 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[22], 0, 0); // "foreach" + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match literal "for" + if (parser->pos + 3 <= parser->input_len && + memcmp(parser->input + parser->pos, "for", 3) == 0) { + parser->pos += 3; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "for" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (parser->success) { + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + parse_AssignableNameList(parser); + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match literal "in" + if (parser->pos + 2 <= parser->input_len && + memcmp(parser->input + parser->pos, "in", 2) == 0) { + parser->pos += 2; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "in" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (parser->success) { + { // Choice + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match single character "*" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 42) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "*" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[47], 0, 0); // "unpack" + } + if (parser->success) { + parse_Exp(parser); + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_Exp(parser); + } + } + } + } + } + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "CompForEach", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "CompForEach", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_CompInner(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "CompInner", start); +#endif + + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Choice + parse_CompForEach(parser); + + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_CompFor(parser); + } + } + if (parser->success) { + { // Zero or more repetitions + while (true) { + parse_CompClause(parser); + if (!parser->success) { + break; + } + } + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "CompInner", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "CompInner", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_Comprehension(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "Comprehension", start); +#endif + + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 7 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[9], 0, 0); // "comprehension" + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match single character "[" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 91) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "[" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + parse_Exp(parser); + if (parser->success) { + parse_CompInner(parser); + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match single character "]" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 93) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "]" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + } + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "Comprehension", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "Comprehension", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_Do(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "Do", start); +#endif + + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 5 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[13], 0, 0); // "do" + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match literal "do" + if (parser->pos + 2 <= parser->input_len && + memcmp(parser->input + parser->pos, "do", 2) == 0) { + parser->pos += 2; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "do" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (parser->success) { + parse_Body(parser); + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "Do", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "Do", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_DotChainItem(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "DotChainItem", start); +#endif + + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[14], 0, 0); // "dot" + } + if (parser->success) { + { // Match single character "." + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 46) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "." + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + parse_NameRaw(parser); + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "DotChainItem", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "DotChainItem", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_DoubleString(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "DoubleString", start); +#endif + + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 4 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[42], 0, 0); // "string" + } + if (parser->success) { + { // Capture + size_t start_pos = parser->pos; + { // Match single character "\"" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 34) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "\\\"" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_STR, 0, start_pos, parser->pos - start_pos); + } + } + if (parser->success) { + { // Zero or more repetitions + while (true) { + { // Choice + { // Capture + size_t start_pos = parser->pos; + { // At least 1 repetitions + REMEMBER_INPUT_POSITION(parser, pos); + size_t rep_count = 0; + + while (true) { + { // Sequence with 2 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match literal "#{" + if (parser->pos + 2 <= parser->input_len && + memcmp(parser->input + parser->pos, "#{", 2) == 0) { + parser->pos += 2; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "#{" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (parser->success) { + parse_DoubleStringInner(parser); + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + + if (!parser->success) { + break; + } + + rep_count += 1; + } + + // Don't recover if labeled failure was thrown + if (parser->throw_label) { + // Keep failure state, propagate labeled failure + } else if (rep_count >= 1) { + parser->success = true; + } else { + RESTORE_INPUT_POSITION(parser, pos); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected 1 repetitions at position %zu", parser->pos); +#endif + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_STR, 0, start_pos, parser->pos - start_pos); + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_DoubleStringInterp(parser); + } + } + if (!parser->success) { + break; + } + } + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + } + if (parser->success) { + { // Match single character "\"" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 34) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "\\\"" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "DoubleString", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "DoubleString", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_DoubleStringInner(Parser *parser) { + size_t start = parser->pos; + // Position-pure rule (no captures, labels, or other state): a + // single-slot memo short-circuits the repeated calls that backtracking + // alternatives make at the same position + if (parser->memo[2].pos == start + 1) { + if (parser->memo[2].endpos == (size_t)-1) { + parser->success = false; + return false; + } + parser->pos = parser->memo[2].endpos; + parser->success = true; + return true; + } + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "DoubleStringInner", start); +#endif + + { // Choice + { // Choice + { // Match literal "\\\"" + if (parser->pos + 2 <= parser->input_len && + memcmp(parser->input + parser->pos, "\\\"", 2) == 0) { + parser->pos += 2; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "\\\"" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Match literal "\\\\" + if (parser->pos + 2 <= parser->input_len && + memcmp(parser->input + parser->pos, "\\\\", 2) == 0) { + parser->pos += 2; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "\\\\" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match single character "\"" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 34) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "\\\"" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (parser->success) { + { // Match any 1 characters + if (parser->pos + 1 <= parser->input_len) { + parser->pos += 1; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected at least 1 more characters at position %zu", parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "DoubleStringInner", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "DoubleStringInner", parser->pos); + } +#endif + parser->memo[2].pos = start + 1; + parser->memo[2].endpos = parser->success ? parser->pos : (size_t)-1; + + parser->depth -= 1; + return parser->success; +} + +static bool parse_DoubleStringInterp(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "DoubleStringInterp", start); +#endif + + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 5 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[26], 0, 0); // "interpolate" + } + if (parser->success) { + { // Match literal "#{" + if (parser->pos + 2 <= parser->input_len && + memcmp(parser->input + parser->pos, "#{", 2) == 0) { + parser->pos += 2; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "#{" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + parse_Exp(parser); + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match single character "}" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 125) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "}" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "DoubleStringInterp", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "DoubleStringInterp", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_EmptyLine(Parser *parser) { + size_t start = parser->pos; + // Position-pure rule (no captures, labels, or other state): a + // single-slot memo short-circuits the repeated calls that backtracking + // alternatives make at the same position + if (parser->memo[3].pos == start + 1) { + if (parser->memo[3].endpos == (size_t)-1) { + parser->success = false; + return false; + } + parser->pos = parser->memo[3].endpos; + parser->success = true; + return true; + } + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "EmptyLine", start); +#endif + + parse_SpaceBreak(parser); + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "EmptyLine", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "EmptyLine", parser->pos); + } +#endif + parser->memo[3].pos = start + 1; + parser->memo[3].endpos = parser->success ? parser->pos : (size_t)-1; + + parser->depth -= 1; + return parser->success; +} + +static bool parse_Exp(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "Exp", start); +#endif + + { // Transform Capture (Cfn id=6) + size_t fn_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_FN_OPEN, __cmt_refs[6], parser->pos, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_Value(parser); + if (parser->success) { + { // Zero or more repetitions + while (true) { + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_BinaryOperator(parser); + if (parser->success) { + parse_Value(parser); + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + if (!parser->success) { + break; + } + } + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_FN_CLOSE, 0, parser->pos, 0); + } else { + parser->cap_len = fn_cap_start; + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "Exp", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "Exp", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_ExpList(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "ExpList", start); +#endif + + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_Exp(parser); + if (parser->success) { + { // Zero or more repetitions + while (true) { + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match single character "," + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 44) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "," + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + parse_Exp(parser); + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + if (!parser->success) { + break; + } + } + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "ExpList", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "ExpList", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_ExpListLow(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "ExpListLow", start); +#endif + + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_Exp(parser); + if (parser->success) { + { // Zero or more repetitions + while (true) { + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Choice + { // Sequence with 2 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match single character "," + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 44) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "," + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match single character ";" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 59) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + ";" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + } + } + if (parser->success) { + parse_Exp(parser); + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + if (!parser->success) { + break; + } + } + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "ExpListLow", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "ExpListLow", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_Export(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "Export", start); +#endif + + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 5 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[18], 0, 0); // "export" + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match literal "export" + if (parser->pos + 6 <= parser->input_len && + memcmp(parser->input + parser->pos, "export", 6) == 0) { + parser->pos += 6; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "export" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (parser->success) { + { // FIRST-byte dispatched ordered choice + unsigned long long pgen_dispatch_mask; + if (parser->pos < parser->input_len) { + switch ((unsigned char)parser->input[parser->pos]) { + case 99: + pgen_dispatch_mask = 0x0000000000000009ULL; + break; + case 42: + pgen_dispatch_mask = 0x000000000000000aULL; + break; + case 94: + pgen_dispatch_mask = 0x000000000000000cULL; + break; + case 9: + case 32: + case 45: + pgen_dispatch_mask = 0x000000000000000fULL; + break; + default: + pgen_dispatch_mask = 0x0000000000000008ULL; + break; + } + } else { + pgen_dispatch_mask = 0x0000000000000008ULL; + } + + parser->success = false; + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 0))) { + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[7], 0, 0); // "class" + } + if (parser->success) { + parse_ClassDecl(parser); + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 1))) { + if ((pgen_dispatch_mask & 0x0000000000000001ULL) != 0x0000000000000001ULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Capture + size_t start_pos = parser->pos; + { // Match single character "*" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 42) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "*" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_STR, 0, start_pos, parser->pos - start_pos); + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 2))) { + if ((pgen_dispatch_mask & 0x0000000000000003ULL) != 0x0000000000000003ULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Capture + size_t start_pos = parser->pos; + { // Match single character "^" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 94) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "^" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_STR, 0, start_pos, parser->pos - start_pos); + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 3))) { + if ((pgen_dispatch_mask & 0x0000000000000007ULL) != 0x0000000000000007ULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + parse_NameList(parser); + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match single character "=" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 61) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "=" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + parse_ExpListLow(parser); + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + if (!parser->success && !parser->throw_label) { + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + if (pgen_dispatch_mask != 0x000000000000000fULL) { + // Some alternatives were skipped: replay the whole choice in original + // order so error_message reports the same failure the undispatched + // parser would. Every alternative fails, so this only affects error + // state. + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[7], 0, 0); // "class" + } + if (parser->success) { + parse_ClassDecl(parser); + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Capture + size_t start_pos = parser->pos; + { // Match single character "*" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 42) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "*" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_STR, 0, start_pos, parser->pos - start_pos); + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Capture + size_t start_pos = parser->pos; + { // Match single character "^" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 94) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "^" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_STR, 0, start_pos, parser->pos - start_pos); + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + parse_NameList(parser); + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match single character "=" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 61) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "=" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + parse_ExpListLow(parser); + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + } +#endif + } + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "Export", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "Export", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_File(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "File", start); +#endif + + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + parse_Shebang(parser); + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + if (parser->success) { + { // Choice + parse_Block(parser); + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Match literal "" + if (parser->pos + 0 <= parser->input_len && + memcmp(parser->input + parser->pos, "", 0) == 0) { + parser->pos += 0; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "File", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "File", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_FnArgDef(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "FnArgDef", start); +#endif + + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Choice + { // Choice + parse_Name(parser); + + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_SelfName(parser); + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_TableLit(parser); + } + } + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match single character "=" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 61) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "=" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + parse_Exp(parser); + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "FnArgDef", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "FnArgDef", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_FnArgDefList(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "FnArgDefList", start); +#endif + + { // Choice + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + parse_FnArgDef(parser); + if (parser->success) { + { // Zero or more repetitions + while (true) { + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + { // Choice + { // Sequence with 2 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match single character "," + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 44) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "," + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_Break(parser); + } + } + if (parser->success) { + parse_White(parser); + if (parser->success) { + parse_FnArgDef(parser); + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + if (!parser->success) { + break; + } + } + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + } + if (parser->success) { + { // Zero or more repetitions + while (true) { + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + { // Choice + { // Sequence with 2 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match single character "," + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 44) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "," + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_Break(parser); + } + } + if (parser->success) { + parse_White(parser); + if (parser->success) { + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + parse_VarArg(parser); + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + if (!parser->success) { + break; + } + } + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + parse_VarArg(parser); + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "FnArgDefList", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "FnArgDefList", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_FnArgs(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "FnArgs", start); +#endif + + { // Choice + { // Sequence with 6 patterns + REMEMBER_POSITION(parser, pos); + + { // Match single character "(" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 40) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "(" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + { // Zero or more repetitions + while (true) { + parse_SpaceBreak(parser); + if (!parser->success) { + break; + } + } + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + } + if (parser->success) { + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + parse_FnArgsExpList(parser); + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + if (parser->success) { + { // Zero or more repetitions + while (true) { + parse_SpaceBreak(parser); + if (!parser->success) { + break; + } + } + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match single character ")" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 41) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + ")" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Sequence with 4 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match single character "!" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 33) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "!" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match single character "=" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 61) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "=" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (parser->success) { + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Match literal "" + if (parser->pos + 0 <= parser->input_len && + memcmp(parser->input + parser->pos, "", 0) == 0) { + parser->pos += 0; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "FnArgs", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "FnArgs", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_FnArgsDef(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "FnArgsDef", start); +#endif + + { // Choice + { // Sequence with 8 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match single character "(" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 40) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "(" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + parse_White(parser); + if (parser->success) { + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + parse_FnArgDefList(parser); + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + if (parser->success) { + { // Choice + { // Sequence with 4 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match literal "using" + if (parser->pos + 5 <= parser->input_len && + memcmp(parser->input + parser->pos, "using", 5) == 0) { + parser->pos += 5; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "using" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (parser->success) { + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Choice + parse_NameList(parser); + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match literal "nil" + if (parser->pos + 3 <= parser->input_len && + memcmp(parser->input + parser->pos, "nil", 3) == 0) { + parser->pos += 3; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "nil" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Match literal "" + if (parser->pos + 0 <= parser->input_len && + memcmp(parser->input + parser->pos, "", 0) == 0) { + parser->pos += 0; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + } + if (parser->success) { + parse_White(parser); + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match single character ")" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 41) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + ")" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + } + } + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Match literal "" + if (parser->pos + 0 <= parser->input_len && + memcmp(parser->input + parser->pos, "", 0) == 0) { + parser->pos += 0; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + if (parser->success) { + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Match literal "" + if (parser->pos + 0 <= parser->input_len && + memcmp(parser->input + parser->pos, "", 0) == 0) { + parser->pos += 0; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "FnArgsDef", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "FnArgsDef", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_FnArgsExpList(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "FnArgsExpList", start); +#endif + + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_Exp(parser); + if (parser->success) { + { // Zero or more repetitions + while (true) { + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + { // Choice + parse_Break(parser); + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match single character "," + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 44) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "," + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + } + } + if (parser->success) { + parse_White(parser); + if (parser->success) { + parse_Exp(parser); + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + if (!parser->success) { + break; + } + } + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "FnArgsExpList", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "FnArgsExpList", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_For(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "For", start); +#endif + + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 12 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[21], 0, 0); // "for" + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match literal "for" + if (parser->pos + 3 <= parser->input_len && + memcmp(parser->input + parser->pos, "for", 3) == 0) { + parser->pos += 3; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "for" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (parser->success) { + { // Indenter cpush (stack 1): push constant 0 + pgen_ind_push(parser, 1, 0); + } + if (parser->success) { + parse_Name(parser); + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match single character "=" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 61) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "=" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 5 patterns + REMEMBER_POSITION(parser, pos); + + parse_Exp(parser); + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match single character "," + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 44) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "," + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + parse_Exp(parser); + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match single character "," + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 44) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "," + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + parse_Exp(parser); + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + if (parser->success) { + { // Indenter pop (stack 1) + if (!pgen_ind_pop(parser, 1)) { + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Indenter stack 1 is empty at position %zu", parser->pos); +#endif + } + } + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + { // Sequence with 3 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match literal "do" + if (parser->pos + 2 <= parser->input_len && + memcmp(parser->input + parser->pos, "do", 2) == 0) { + parser->pos += 2; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "do" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + } + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + if (parser->success) { + parse_Body(parser); + } + } + } + } + } + } + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "For", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "For", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_ForEach(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "ForEach", start); +#endif + + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 13 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[22], 0, 0); // "foreach" + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match literal "for" + if (parser->pos + 3 <= parser->input_len && + memcmp(parser->input + parser->pos, "for", 3) == 0) { + parser->pos += 3; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "for" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (parser->success) { + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + parse_AssignableNameList(parser); + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match literal "in" + if (parser->pos + 2 <= parser->input_len && + memcmp(parser->input + parser->pos, "in", 2) == 0) { + parser->pos += 2; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "in" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (parser->success) { + { // Indenter cpush (stack 1): push constant 0 + pgen_ind_push(parser, 1, 0); + } + if (parser->success) { + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Choice + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match single character "*" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 42) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "*" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[47], 0, 0); // "unpack" + } + if (parser->success) { + parse_Exp(parser); + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_ExpList(parser); + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + if (parser->success) { + { // Indenter pop (stack 1) + if (!pgen_ind_pop(parser, 1)) { + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Indenter stack 1 is empty at position %zu", parser->pos); +#endif + } + } + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + { // Sequence with 3 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match literal "do" + if (parser->pos + 2 <= parser->input_len && + memcmp(parser->input + parser->pos, "do", 2) == 0) { + parser->pos += 2; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "do" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + } + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + if (parser->success) { + parse_Body(parser); + } + } + } + } + } + } + } + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "ForEach", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "ForEach", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_FunLit(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "FunLit", start); +#endif + + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 4 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[20], 0, 0); // "fndef" + } + if (parser->success) { + parse_FnArgsDef(parser); + if (parser->success) { + { // Choice + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match literal "->" + if (parser->pos + 2 <= parser->input_len && + memcmp(parser->input + parser->pos, "->", 2) == 0) { + parser->pos += 2; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "->" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[40], 0, 0); // "slim" + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match literal "=>" + if (parser->pos + 2 <= parser->input_len && + memcmp(parser->input + parser->pos, "=>", 2) == 0) { + parser->pos += 2; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "=>" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[19], 0, 0); // "fat" + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + } + if (parser->success) { + { // Choice + parse_Body(parser); + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Match literal "" + if (parser->pos + 0 <= parser->input_len && + memcmp(parser->input + parser->pos, "", 0) == 0) { + parser->pos += 0; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "FunLit", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "FunLit", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_If(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "If", start); +#endif + + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 9 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[23], 0, 0); // "if" + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match literal "if" + if (parser->pos + 2 <= parser->input_len && + memcmp(parser->input + parser->pos, "if", 2) == 0) { + parser->pos += 2; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "if" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (parser->success) { + parse_IfCond(parser); + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + { // Sequence with 3 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match literal "then" + if (parser->pos + 4 <= parser->input_len && + memcmp(parser->input + parser->pos, "then", 4) == 0) { + parser->pos += 4; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "then" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + } + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + if (parser->success) { + parse_Body(parser); + if (parser->success) { + { // Zero or more repetitions + while (true) { + parse_IfElseIf(parser); + if (!parser->success) { + break; + } + } + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + } + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + parse_IfElse(parser); + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + } + } + } + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "If", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "If", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_IfCond(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "IfCond", start); +#endif + + { // Transform Capture (Cfn id=0) + size_t fn_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_FN_OPEN, __cmt_refs[0], parser->pos, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_Exp(parser); + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + parse_Assign(parser); + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_FN_CLOSE, 0, parser->pos, 0); + } else { + parser->cap_len = fn_cap_start; + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "IfCond", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "IfCond", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_IfElse(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "IfElse", start); +#endif + + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 6 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[15], 0, 0); // "else" + } + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + parse_Break(parser); + if (parser->success) { + { // Zero or more repetitions + while (true) { + parse_EmptyLine(parser); + if (!parser->success) { + break; + } + } + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + } + if (parser->success) { + parse_CheckIndent(parser); + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match literal "else" + if (parser->pos + 4 <= parser->input_len && + memcmp(parser->input + parser->pos, "else", 4) == 0) { + parser->pos += 4; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "else" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (parser->success) { + parse_Body(parser); + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "IfElse", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "IfElse", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_IfElseIf(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "IfElseIf", start); +#endif + + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 8 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[16], 0, 0); // "elseif" + } + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + parse_Break(parser); + if (parser->success) { + { // Zero or more repetitions + while (true) { + parse_EmptyLine(parser); + if (!parser->success) { + break; + } + } + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + } + if (parser->success) { + parse_CheckIndent(parser); + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match literal "elseif" + if (parser->pos + 6 <= parser->input_len && + memcmp(parser->input + parser->pos, "elseif", 6) == 0) { + parser->pos += 6; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "elseif" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (parser->success) { + { // Transform Capture (Cfn id=2) + size_t fn_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_FN_OPEN, __cmt_refs[2], parser->pos, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Position Capture + pgen_cap_push(parser, PGEN_CAP_POS, 0, parser->pos, 0); + } + if (parser->success) { + parse_IfCond(parser); + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_FN_CLOSE, 0, parser->pos, 0); + } else { + parser->cap_len = fn_cap_start; + } + } + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + { // Sequence with 3 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match literal "then" + if (parser->pos + 4 <= parser->input_len && + memcmp(parser->input + parser->pos, "then", 4) == 0) { + parser->pos += 4; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "then" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + } + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + if (parser->success) { + parse_Body(parser); + } + } + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "IfElseIf", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "IfElseIf", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_Import(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "Import", start); +#endif + + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 10 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[24], 0, 0); // "import" + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match literal "import" + if (parser->pos + 6 <= parser->input_len && + memcmp(parser->input + parser->pos, "import", 6) == 0) { + parser->pos += 6; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "import" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (parser->success) { + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + parse_ImportNameList(parser); + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + if (parser->success) { + { // Zero or more repetitions + while (true) { + parse_SpaceBreak(parser); + if (!parser->success) { + break; + } + } + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match literal "from" + if (parser->pos + 4 <= parser->input_len && + memcmp(parser->input + parser->pos, "from", 4) == 0) { + parser->pos += 4; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "from" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (parser->success) { + parse_Exp(parser); + } + } + } + } + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "Import", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "Import", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_ImportName(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "ImportName", start); +#endif + + { // Choice + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match single character "\\" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 92) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "\\\\" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[8], 0, 0); // "colon" + } + if (parser->success) { + parse_Name(parser); + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_Name(parser); + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "ImportName", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "ImportName", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_ImportNameList(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "ImportNameList", start); +#endif + + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + { // Zero or more repetitions + while (true) { + parse_SpaceBreak(parser); + if (!parser->success) { + break; + } + } + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + } + if (parser->success) { + parse_ImportName(parser); + if (parser->success) { + { // Zero or more repetitions + while (true) { + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Choice + { // At least 1 repetitions + REMEMBER_INPUT_POSITION(parser, pos); + size_t rep_count = 0; + + while (true) { + parse_SpaceBreak(parser); + + if (!parser->success) { + break; + } + + rep_count += 1; + } + + // Don't recover if labeled failure was thrown + if (parser->throw_label) { + // Keep failure state, propagate labeled failure + } else if (rep_count >= 1) { + parser->success = true; + } else { + RESTORE_INPUT_POSITION(parser, pos); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected 1 repetitions at position %zu", parser->pos); +#endif + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Sequence with 3 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match single character "," + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 44) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "," + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + { // Zero or more repetitions + while (true) { + parse_SpaceBreak(parser); + if (!parser->success) { + break; + } + } + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + } + } + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + } + } + if (parser->success) { + parse_ImportName(parser); + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + if (!parser->success) { + break; + } + } + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "ImportNameList", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "ImportNameList", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_InBlock(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "InBlock", start); +#endif + + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + parse_Advance(parser); + if (parser->success) { + parse_Block(parser); + if (parser->success) { + parse_PopIndent(parser); + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "InBlock", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "InBlock", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_Invoke(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "Invoke", start); +#endif + + { // FIRST-byte dispatched ordered choice + unsigned long long pgen_dispatch_mask; + if (parser->pos < parser->input_len) { + switch ((unsigned char)parser->input[parser->pos]) { + case 9: + case 32: + case 33: + case 40: + case 45: + pgen_dispatch_mask = 0x0000000000000009ULL; + break; + case 39: + pgen_dispatch_mask = 0x000000000000000aULL; + break; + case 34: + pgen_dispatch_mask = 0x000000000000000cULL; + break; + default: + pgen_dispatch_mask = 0x0000000000000008ULL; + break; + } + } else { + pgen_dispatch_mask = 0x0000000000000008ULL; + } + + parser->success = false; + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 0))) { + parser->success = true; + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[4], 0, 0); // "call" + } + if (parser->success) { + parse_FnArgs(parser); + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 1))) { + if ((pgen_dispatch_mask & 0x0000000000000001ULL) != 0x0000000000000001ULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[4], 0, 0); // "call" + } + if (parser->success) { + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + parse_SingleString(parser); + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 2))) { + if ((pgen_dispatch_mask & 0x0000000000000003ULL) != 0x0000000000000003ULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[4], 0, 0); // "call" + } + if (parser->success) { + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + parse_DoubleString(parser); + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 3))) { + if ((pgen_dispatch_mask & 0x0000000000000007ULL) != 0x0000000000000007ULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Lookahead (match without consuming input) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match single character "[" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 91) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "[" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, but we don't consume any input + RESTORE_INPUT_POSITION(parser, pos); + } + } + if (parser->success) { + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[4], 0, 0); // "call" + } + if (parser->success) { + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + parse_LuaString(parser); + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + if (!parser->success && !parser->throw_label) { + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + if (pgen_dispatch_mask != 0x000000000000000fULL) { + // Some alternatives were skipped: replay the whole choice in original + // order so error_message reports the same failure the undispatched + // parser would. Every alternative fails, so this only affects error + // state. + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[4], 0, 0); // "call" + } + if (parser->success) { + parse_FnArgs(parser); + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[4], 0, 0); // "call" + } + if (parser->success) { + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + parse_SingleString(parser); + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[4], 0, 0); // "call" + } + if (parser->success) { + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + parse_DoubleString(parser); + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Lookahead (match without consuming input) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match single character "[" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 91) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "[" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, but we don't consume any input + RESTORE_INPUT_POSITION(parser, pos); + } + } + if (parser->success) { + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[4], 0, 0); // "call" + } + if (parser->success) { + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + parse_LuaString(parser); + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + } +#endif + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "Invoke", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "Invoke", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_InvokeArgs(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "InvokeArgs", start); +#endif + + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match single character "-" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 45) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "-" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (parser->success) { + { // Choice + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_ExpList(parser); + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + { // Choice + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match single character "," + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 44) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "," + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + { // Choice + parse_TableBlock(parser); + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Sequence with 4 patterns + REMEMBER_POSITION(parser, pos); + + parse_SpaceBreak(parser); + if (parser->success) { + parse_Advance(parser); + if (parser->success) { + parse_ArgBlock(parser); + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + parse_TableBlock(parser); + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_TableBlock(parser); + } + } + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_TableBlock(parser); + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "InvokeArgs", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "InvokeArgs", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_KeyName(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "KeyName", start); +#endif + + { // Choice + parse_SelfName(parser); + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[27], 0, 0); // "key_literal" + } + if (parser->success) { + parse_NameRaw(parser); + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "KeyName", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "KeyName", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_KeyValue(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "KeyValue", start); +#endif + + { // Choice + { // Transform Capture (Cfn id=4) + size_t fn_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_FN_OPEN, __cmt_refs[4], parser->pos, 0); + { // Sequence with 5 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match single character ":" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 58) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + ":" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + parse_SomeSpace(parser); + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (parser->success) { + parse_Name(parser); + if (parser->success) { + { // Position Capture + pgen_cap_push(parser, PGEN_CAP_POS, 0, parser->pos, 0); + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_FN_CLOSE, 0, parser->pos, 0); + } else { + parser->cap_len = fn_cap_start; + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + { // FIRST-byte dispatched ordered choice + unsigned long long pgen_dispatch_mask; + if (parser->pos < parser->input_len) { + switch ((unsigned char)parser->input[parser->pos]) { + case 64: + case 65: + case 66: + case 67: + case 68: + case 69: + case 70: + case 71: + case 72: + case 73: + case 74: + case 75: + case 76: + case 77: + case 78: + case 79: + case 80: + case 81: + case 82: + case 83: + case 84: + case 85: + case 86: + case 87: + case 88: + case 89: + case 90: + case 95: + case 97: + case 98: + case 99: + case 100: + case 101: + case 102: + case 103: + case 104: + case 105: + case 106: + case 107: + case 108: + case 109: + case 110: + case 111: + case 112: + case 113: + case 114: + case 115: + case 116: + case 117: + case 118: + case 119: + case 120: + case 121: + case 122: + pgen_dispatch_mask = 0x0000000000000001ULL; + break; + case 91: + pgen_dispatch_mask = 0x0000000000000002ULL; + break; + case 34: + pgen_dispatch_mask = 0x0000000000000004ULL; + break; + case 39: + pgen_dispatch_mask = 0x0000000000000008ULL; + break; + case 9: + case 32: + case 45: + pgen_dispatch_mask = 0x000000000000000fULL; + break; + default: + pgen_dispatch_mask = 0x0000000000000000ULL; + break; + } + } else { + pgen_dispatch_mask = 0x0000000000000000ULL; + } + + parser->success = false; + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 0))) { + parser->success = true; + parse_KeyName(parser); + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 1))) { + if ((pgen_dispatch_mask & 0x0000000000000001ULL) != 0x0000000000000001ULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + { // Sequence with 5 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match single character "[" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 91) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "[" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + parse_Exp(parser); + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match single character "]" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 93) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "]" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 2))) { + if ((pgen_dispatch_mask & 0x0000000000000003ULL) != 0x0000000000000003ULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + parse_DoubleString(parser); + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 3))) { + if ((pgen_dispatch_mask & 0x0000000000000007ULL) != 0x0000000000000007ULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + parse_SingleString(parser); + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + if (!parser->success && !parser->throw_label) { + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + if (pgen_dispatch_mask != 0x000000000000000fULL) { + // Some alternatives were skipped: replay the whole choice in original + // order so error_message reports the same failure the undispatched + // parser would. Every alternative fails, so this only affects error + // state. + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_KeyName(parser); + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Sequence with 5 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match single character "[" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 91) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "[" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + parse_Exp(parser); + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match single character "]" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 93) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "]" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + parse_DoubleString(parser); + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + parse_SingleString(parser); + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + } +#endif + } + } + if (parser->success) { + { // Match single character ":" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 58) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + ":" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + { // Choice + { // Choice + parse_Exp(parser); + + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_TableBlock(parser); + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // At least 1 repetitions + REMEMBER_INPUT_POSITION(parser, pos); + size_t rep_count = 0; + + while (true) { + parse_SpaceBreak(parser); + + if (!parser->success) { + break; + } + + rep_count += 1; + } + + // Don't recover if labeled failure was thrown + if (parser->throw_label) { + // Keep failure state, propagate labeled failure + } else if (rep_count >= 1) { + parser->success = true; + } else { + RESTORE_INPUT_POSITION(parser, pos); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected 1 repetitions at position %zu", parser->pos); +#endif + } + } + if (parser->success) { + parse_Exp(parser); + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "KeyValue", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "KeyValue", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_KeyValueLine(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "KeyValueLine", start); +#endif + + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + parse_CheckIndent(parser); + if (parser->success) { + parse_KeyValueList(parser); + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + { // Sequence with 2 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match single character "," + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 44) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "," + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "KeyValueLine", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "KeyValueLine", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_KeyValueList(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "KeyValueList", start); +#endif + + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_KeyValue(parser); + if (parser->success) { + { // Zero or more repetitions + while (true) { + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match single character "," + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 44) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "," + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + parse_KeyValue(parser); + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + if (!parser->success) { + break; + } + } + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "KeyValueList", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "KeyValueList", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_Line(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "Line", start); +#endif + + { // Choice + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_CheckIndent(parser); + if (parser->success) { + parse_Statement(parser); + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Lookahead (match without consuming input) + REMEMBER_INPUT_POSITION(parser, pos); + + parse_Stop(parser); + + if (parser->success) { + // Pattern matched, but we don't consume any input + RESTORE_INPUT_POSITION(parser, pos); + } + } + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "Line", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "Line", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_Local(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "Local", start); +#endif + + { // Sequence with 4 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match literal "local" + if (parser->pos + 5 <= parser->input_len && + memcmp(parser->input + parser->pos, "local", 5) == 0) { + parser->pos += 5; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "local" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (parser->success) { + { // Choice + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[11], 0, 0); // "declare_glob" + } + if (parser->success) { + { // Choice + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Capture + size_t start_pos = parser->pos; + { // Match single character "*" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 42) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "*" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_STR, 0, start_pos, parser->pos - start_pos); + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Capture + size_t start_pos = parser->pos; + { // Match single character "^" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 94) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "^" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_STR, 0, start_pos, parser->pos - start_pos); + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[12], 0, 0); // "declare_with_shadows" + } + if (parser->success) { + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + parse_NameList(parser); + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "Local", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "Local", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_LuaString(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "LuaString", start); +#endif + + { // Transform Capture (Cfn id=7) + size_t fn_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_FN_OPEN, __cmt_refs[7], parser->pos, 0); + { // Sequence with 9 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match single character "[" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 91) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "[" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + { // Position Capture + pgen_cap_push(parser, PGEN_CAP_POS, 0, parser->pos, 0); + } + if (parser->success) { + { // Capture Group "lua_eq" + size_t cg_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_GROUP_OPEN, 0, parser->pos, 0); + { // Zero or more repetitions + while (true) { + { // Match single character "=" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 61) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "=" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (!parser->success) { + break; + } + } + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_GROUP_CLOSE, 0, parser->pos, 0); + } else { + parser->cap_len = cg_cap_start; + } + } + if (parser->success) { + { // Position Capture + pgen_cap_push(parser, PGEN_CAP_POS, 0, parser->pos, 0); + } + if (parser->success) { + { // Match single character "[" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 91) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "[" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + parse_Break(parser); + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + if (parser->success) { + { // Capture + size_t start_pos = parser->pos; + { // Zero or more repetitions + while (true) { + { // Sequence with 2 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + parse_LuaStringClose(parser); + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (parser->success) { + { // Match any 1 characters + if (parser->pos + 1 <= parser->input_len) { + parser->pos += 1; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected at least 1 more characters at position %zu", parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + if (!parser->success) { + break; + } + } + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_STR, 0, start_pos, parser->pos - start_pos); + } + } + if (parser->success) { + parse_LuaStringClose(parser); + } + } + } + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_FN_CLOSE, 0, parser->pos, 0); + } else { + parser->cap_len = fn_cap_start; + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "LuaString", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "LuaString", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_LuaStringClose(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "LuaStringClose", start); +#endif + + { // Sequence with 3 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match single character "]" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 93) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "]" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + { // Capture Match Back "lua_eq" + parser->success = pgen_cap_match_back(parser, 0); + if (!parser->success) { + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Capture match back 'lua_eq' failed at position %zu", parser->pos); +#endif + } + } + if (parser->success) { + { // Match single character "]" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 93) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "]" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + } + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "LuaStringClose", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "LuaStringClose", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_Name(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "Name", start); +#endif + + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Sequence with 2 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + { // Trie match for: "continue", "extends", "elseif", "export", "import", "return", "switch", "unless", "break", "class", "local", "using", "while", "else", "from", "then", "when", "with", "and", "for", "not", "do", "if", "in", "or" + REMEMBER_POSITION(parser, trie_start); + size_t last_terminal_pos = 0; + int has_terminal = 0; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 97: // "a" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 110: // "n" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 100: // "d" + parser->pos++; + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + case 98: // "b" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 114: // "r" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 101: // "e" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 97: // "a" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 107: // "k" + parser->pos++; + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + case 99: // "c" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 108: // "l" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 97: // "a" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 115: // "s" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 115: // "s" + parser->pos++; + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + case 111: // "o" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 110: // "n" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 116: // "t" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 105: // "i" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 110: // "n" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 117: // "u" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 101: // "e" + parser->pos++; + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + case 100: // "d" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 111: // "o" + parser->pos++; + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + case 101: // "e" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 108: // "l" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 115: // "s" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 101: // "e" + parser->pos++; + if (!has_terminal || parser->pos > last_terminal_pos) { + last_terminal_pos = parser->pos; + has_terminal = 1; + } + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 105: // "i" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 102: // "f" + parser->pos++; + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + if (!parser->success) { + // Partial match is valid: "else" + parser->success = true; + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + case 120: // "x" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 112: // "p" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 111: // "o" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 114: // "r" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 116: // "t" + parser->pos++; + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + case 116: // "t" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 101: // "e" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 110: // "n" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 100: // "d" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 115: // "s" + parser->pos++; + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + case 102: // "f" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 111: // "o" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 114: // "r" + parser->pos++; + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + case 114: // "r" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 111: // "o" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 109: // "m" + parser->pos++; + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + case 105: // "i" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 102: // "f" + parser->pos++; + break; + case 109: // "m" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 112: // "p" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 111: // "o" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 114: // "r" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 116: // "t" + parser->pos++; + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + case 110: // "n" + parser->pos++; + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + case 108: // "l" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 111: // "o" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 99: // "c" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 97: // "a" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 108: // "l" + parser->pos++; + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + case 110: // "n" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 111: // "o" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 116: // "t" + parser->pos++; + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + case 111: // "o" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 114: // "r" + parser->pos++; + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + case 114: // "r" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 101: // "e" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 116: // "t" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 117: // "u" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 114: // "r" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 110: // "n" + parser->pos++; + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + case 115: // "s" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 119: // "w" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 105: // "i" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 116: // "t" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 99: // "c" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 104: // "h" + parser->pos++; + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + case 116: // "t" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 104: // "h" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 101: // "e" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 110: // "n" + parser->pos++; + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + case 117: // "u" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 110: // "n" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 108: // "l" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 101: // "e" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 115: // "s" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 115: // "s" + parser->pos++; + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + case 115: // "s" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 105: // "i" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 110: // "n" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 103: // "g" + parser->pos++; + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + case 119: // "w" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 104: // "h" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 101: // "e" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 110: // "n" + parser->pos++; + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + case 105: // "i" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 108: // "l" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 101: // "e" + parser->pos++; + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + case 105: // "i" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 116: // "t" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 104: // "h" + parser->pos++; + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + if (!parser->success) { + RESTORE_POSITION(parser, trie_start); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (parser->success) { + parse_NameRaw(parser); + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "Name", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "Name", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_NameList(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "NameList", start); +#endif + + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_Name(parser); + if (parser->success) { + { // Zero or more repetitions + while (true) { + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match single character "," + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 44) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "," + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + parse_Name(parser); + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + if (!parser->success) { + break; + } + } + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "NameList", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "NameList", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_NameOrDestructure(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "NameOrDestructure", start); +#endif + + { // Choice + parse_Name(parser); + + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_TableLit(parser); + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "NameOrDestructure", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "NameOrDestructure", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_NameRaw(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "NameRaw", start); +#endif + + { // Capture + size_t start_pos = parser->pos; + { // Sequence with 2 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + { // Zero or more repetitions + while (true) { + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (!parser->success) { + break; + } + } + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + } + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_STR, 0, start_pos, parser->pos - start_pos); + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "NameRaw", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "NameRaw", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_Num(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "Num", start); +#endif + + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[31], 0, 0); // "number" + } + if (parser->success) { + { // Capture + size_t start_pos = parser->pos; + { // Choice + { // Choice + { // Sequence with 3 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match literal "0x" + if (parser->pos + 2 <= parser->input_len && + memcmp(parser->input + parser->pos, "0x", 2) == 0) { + parser->pos += 2; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "0x" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // At least 1 repetitions + REMEMBER_INPUT_POSITION(parser, pos); + size_t rep_count = 0; + + while (true) { + { // Match character range: "09,af,AF" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 102) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 70))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "0" + " - " + "9" + ", " + "a" + " - " + "f" + ", " + "A" + " - " + "F" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (!parser->success) { + break; + } + + rep_count += 1; + } + + // Don't recover if labeled failure was thrown + if (parser->throw_label) { + // Keep failure state, propagate labeled failure + } else if (rep_count >= 1) { + parser->success = true; + } else { + RESTORE_INPUT_POSITION(parser, pos); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected 1 repetitions at position %zu", parser->pos); +#endif + } + } + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + { // Sequence with 2 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + { // Match character set "uU" + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 117: /* "u" */ + case 85: /* "U" */ + parser->pos++; + break; + default: +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected one of " + "\"uU\"" + " at position %zu", + parser->pos); +#endif + parser->success = false; + } + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected one of " + "\"uU\"" + " at position %zu but reached end of input", + parser->pos); +#endif + parser->success = false; + } + } + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + if (parser->success) { + { // At least 2 repetitions + REMEMBER_INPUT_POSITION(parser, pos); + size_t rep_count = 0; + + while (true) { + { // Match character set "lL" + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 108: /* "l" */ + case 76: /* "L" */ + parser->pos++; + break; + default: +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected one of " + "\"lL\"" + " at position %zu", + parser->pos); +#endif + parser->success = false; + } + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected one of " + "\"lL\"" + " at position %zu but reached end of input", + parser->pos); +#endif + parser->success = false; + } + } + + if (!parser->success) { + break; + } + + rep_count += 1; + } + + // Don't recover if labeled failure was thrown + if (parser->throw_label) { + // Keep failure state, propagate labeled failure + } else if (rep_count >= 2) { + parser->success = true; + } else { + RESTORE_INPUT_POSITION(parser, pos); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected 2 repetitions at position %zu", parser->pos); +#endif + } + } + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + } + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Sequence with 3 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + { // At least 1 repetitions + REMEMBER_INPUT_POSITION(parser, pos); + size_t rep_count = 0; + + while (true) { + { // Match character range: "09" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "0" + " - " + "9" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (!parser->success) { + break; + } + + rep_count += 1; + } + + // Don't recover if labeled failure was thrown + if (parser->throw_label) { + // Keep failure state, propagate labeled failure + } else if (rep_count >= 1) { + parser->success = true; + } else { + RESTORE_INPUT_POSITION(parser, pos); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected 1 repetitions at position %zu", parser->pos); +#endif + } + } + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + { // Match character set "uU" + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 117: /* "u" */ + case 85: /* "U" */ + parser->pos++; + break; + default: +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected one of " + "\"uU\"" + " at position %zu", + parser->pos); +#endif + parser->success = false; + } + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected one of " + "\"uU\"" + " at position %zu but reached end of input", + parser->pos); +#endif + parser->success = false; + } + } + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + if (parser->success) { + { // At least 2 repetitions + REMEMBER_INPUT_POSITION(parser, pos); + size_t rep_count = 0; + + while (true) { + { // Match character set "lL" + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 108: /* "l" */ + case 76: /* "L" */ + parser->pos++; + break; + default: +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected one of " + "\"lL\"" + " at position %zu", + parser->pos); +#endif + parser->success = false; + } + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected one of " + "\"lL\"" + " at position %zu but reached end of input", + parser->pos); +#endif + parser->success = false; + } + } + + if (!parser->success) { + break; + } + + rep_count += 1; + } + + // Don't recover if labeled failure was thrown + if (parser->throw_label) { + // Keep failure state, propagate labeled failure + } else if (rep_count >= 2) { + parser->success = true; + } else { + RESTORE_INPUT_POSITION(parser, pos); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected 2 repetitions at position %zu", parser->pos); +#endif + } + } + } + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + { // Choice + { // Sequence with 2 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + { // At least 1 repetitions + REMEMBER_INPUT_POSITION(parser, pos); + size_t rep_count = 0; + + while (true) { + { // Match character range: "09" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "0" + " - " + "9" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (!parser->success) { + break; + } + + rep_count += 1; + } + + // Don't recover if labeled failure was thrown + if (parser->throw_label) { + // Keep failure state, propagate labeled failure + } else if (rep_count >= 1) { + parser->success = true; + } else { + RESTORE_INPUT_POSITION(parser, pos); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected 1 repetitions at position %zu", parser->pos); +#endif + } + } + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + { // Sequence with 2 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match single character "." + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 46) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "." + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + { // At least 1 repetitions + REMEMBER_INPUT_POSITION(parser, pos); + size_t rep_count = 0; + + while (true) { + { // Match character range: "09" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "0" + " - " + "9" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (!parser->success) { + break; + } + + rep_count += 1; + } + + // Don't recover if labeled failure was thrown + if (parser->throw_label) { + // Keep failure state, propagate labeled failure + } else if (rep_count >= 1) { + parser->success = true; + } else { + RESTORE_INPUT_POSITION(parser, pos); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected 1 repetitions at position %zu", parser->pos); +#endif + } + } + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match single character "." + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 46) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "." + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + { // At least 1 repetitions + REMEMBER_INPUT_POSITION(parser, pos); + size_t rep_count = 0; + + while (true) { + { // Match character range: "09" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "0" + " - " + "9" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (!parser->success) { + break; + } + + rep_count += 1; + } + + // Don't recover if labeled failure was thrown + if (parser->throw_label) { + // Keep failure state, propagate labeled failure + } else if (rep_count >= 1) { + parser->success = true; + } else { + RESTORE_INPUT_POSITION(parser, pos); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected 1 repetitions at position %zu", parser->pos); +#endif + } + } + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + } + } + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + { // Sequence with 3 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character set "eE" + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 101: /* "e" */ + case 69: /* "E" */ + parser->pos++; + break; + default: +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected one of " + "\"eE\"" + " at position %zu", + parser->pos); +#endif + parser->success = false; + } + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected one of " + "\"eE\"" + " at position %zu but reached end of input", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + { // Match single character "-" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 45) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "-" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + if (parser->success) { + { // At least 1 repetitions + REMEMBER_INPUT_POSITION(parser, pos); + size_t rep_count = 0; + + while (true) { + { // Match character range: "09" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "0" + " - " + "9" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (!parser->success) { + break; + } + + rep_count += 1; + } + + // Don't recover if labeled failure was thrown + if (parser->throw_label) { + // Keep failure state, propagate labeled failure + } else if (rep_count >= 1) { + parser->success = true; + } else { + RESTORE_INPUT_POSITION(parser, pos); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected 1 repetitions at position %zu", parser->pos); +#endif + } + } + } + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_STR, 0, start_pos, parser->pos - start_pos); + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "Num", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "Num", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_Parens(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "Parens", start); +#endif + + { // Sequence with 7 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match single character "(" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 40) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "(" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + { // Zero or more repetitions + while (true) { + parse_SpaceBreak(parser); + if (!parser->success) { + break; + } + } + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + } + if (parser->success) { + parse_Exp(parser); + if (parser->success) { + { // Zero or more repetitions + while (true) { + parse_SpaceBreak(parser); + if (!parser->success) { + break; + } + } + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match single character ")" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 41) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + ")" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + } + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "Parens", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "Parens", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_PopIndent(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "PopIndent", start); +#endif + + { // Indenter pop (stack 0) + if (!pgen_ind_pop(parser, 0)) { + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Indenter stack 0 is empty at position %zu", parser->pos); +#endif + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "PopIndent", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "PopIndent", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_PreventIndent(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "PreventIndent", start); +#endif + + { // Indenter prevent (stack 0): push sentinel so nested advance fails + pgen_ind_push(parser, 0, PGEN_IND_PREVENT_SENTINEL); + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "PreventIndent", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "PreventIndent", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_PushIndent(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "PushIndent", start); +#endif + + { // Indenter push (stack 0): consume whitespace, push measured width + size_t ind_end; + int ind_width = pgen_ind_measure(parser, &ind_end, 4); + pgen_ind_push(parser, 0, ind_width); + parser->pos = ind_end; + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "PushIndent", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "PushIndent", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_Return(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "Return", start); +#endif + + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 5 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[35], 0, 0); // "return" + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match literal "return" + if (parser->pos + 6 <= parser->input_len && + memcmp(parser->input + parser->pos, "return", 6) == 0) { + parser->pos += 6; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "return" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (parser->success) { + { // Choice + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[17], 0, 0); // "explist" + } + if (parser->success) { + parse_ExpListLow(parser); + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Capture + size_t start_pos = parser->pos; + { // Match literal "" + if (parser->pos + 0 <= parser->input_len && + memcmp(parser->input + parser->pos, "", 0) == 0) { + parser->pos += 0; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_STR, 0, start_pos, parser->pos - start_pos); + } + } + } + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "Return", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "Return", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_SelfName(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "SelfName", start); +#endif + + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match single character "@" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 64) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "@" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + { // Choice + { // Choice + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Match single character "@" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 64) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "@" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + { // Choice + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[38], 0, 0); // "self_class" + } + if (parser->success) { + parse_NameRaw(parser); + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[37], 0, 0); // "self.__class" + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[36], 0, 0); // "self" + } + if (parser->success) { + parse_NameRaw(parser); + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[36], 0, 0); // "self" + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "SelfName", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "SelfName", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_Shebang(Parser *parser) { + size_t start = parser->pos; + // Position-pure rule (no captures, labels, or other state): a + // single-slot memo short-circuits the repeated calls that backtracking + // alternatives make at the same position + if (parser->memo[4].pos == start + 1) { + if (parser->memo[4].endpos == (size_t)-1) { + parser->success = false; + return false; + } + parser->pos = parser->memo[4].endpos; + parser->success = true; + return true; + } + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "Shebang", start); +#endif + + { // Sequence with 2 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match literal "#!" + if (parser->pos + 2 <= parser->input_len && + memcmp(parser->input + parser->pos, "#!", 2) == 0) { + parser->pos += 2; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "#!" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // Zero or more repetitions + while (true) { + { // Sequence with 2 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + parse_Stop(parser); + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (parser->success) { + { // Match any 1 characters + if (parser->pos + 1 <= parser->input_len) { + parser->pos += 1; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected at least 1 more characters at position %zu", parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + if (!parser->success) { + break; + } + } + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + } + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "Shebang", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "Shebang", parser->pos); + } +#endif + parser->memo[4].pos = start + 1; + parser->memo[4].endpos = parser->success ? parser->pos : (size_t)-1; + + parser->depth -= 1; + return parser->success; +} + +static bool parse_SimpleValue(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "SimpleValue", start); +#endif + + { // FIRST-byte dispatched ordered choice + unsigned long long pgen_dispatch_mask; + if (parser->pos < parser->input_len) { + switch ((unsigned char)parser->input[parser->pos]) { + case 105: + pgen_dispatch_mask = 0x0000000000000101ULL; + break; + case 117: + pgen_dispatch_mask = 0x0000000000000102ULL; + break; + case 115: + pgen_dispatch_mask = 0x0000000000000104ULL; + break; + case 99: + pgen_dispatch_mask = 0x0000000000000110ULL; + break; + case 102: + pgen_dispatch_mask = 0x0000000000000160ULL; + break; + case 119: + pgen_dispatch_mask = 0x0000000000000188ULL; + break; + case 35: + pgen_dispatch_mask = 0x0000000000000500ULL; + break; + case 126: + pgen_dispatch_mask = 0x0000000000000900ULL; + break; + case 110: + pgen_dispatch_mask = 0x0000000000001100ULL; + break; + case 123: + pgen_dispatch_mask = 0x0000000000006100ULL; + break; + case 91: + pgen_dispatch_mask = 0x0000000000008100ULL; + break; + case 40: + case 61: + pgen_dispatch_mask = 0x0000000000010100ULL; + break; + case 46: + case 48: + case 49: + case 50: + case 51: + case 52: + case 53: + case 54: + case 55: + case 56: + case 57: + pgen_dispatch_mask = 0x0000000000020100ULL; + break; + case 9: + case 32: + case 45: + pgen_dispatch_mask = 0x000000000003ffffULL; + break; + default: + pgen_dispatch_mask = 0x0000000000000100ULL; + break; + } + } else { + pgen_dispatch_mask = 0x0000000000000100ULL; + } + + parser->success = false; + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 0))) { + parser->success = true; + parse_If(parser); + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 1))) { + if ((pgen_dispatch_mask & 0x0000000000000001ULL) != 0x0000000000000001ULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + parse_Unless(parser); + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 2))) { + if ((pgen_dispatch_mask & 0x0000000000000003ULL) != 0x0000000000000003ULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + parse_Switch(parser); + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 3))) { + if ((pgen_dispatch_mask & 0x0000000000000007ULL) != 0x0000000000000007ULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + parse_With(parser); + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 4))) { + if ((pgen_dispatch_mask & 0x000000000000000fULL) != 0x000000000000000fULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + parse_ClassDecl(parser); + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 5))) { + if ((pgen_dispatch_mask & 0x000000000000001fULL) != 0x000000000000001fULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + parse_ForEach(parser); + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 6))) { + if ((pgen_dispatch_mask & 0x000000000000003fULL) != 0x000000000000003fULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + parse_For(parser); + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 7))) { + if ((pgen_dispatch_mask & 0x000000000000007fULL) != 0x000000000000007fULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + parse_While(parser); + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 8))) { + if ((pgen_dispatch_mask & 0x00000000000000ffULL) != 0x00000000000000ffULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Indenter ctop (stack 1): top ne 0 + PgenIndStack *ind_s = &parser->ind_stacks[1]; + if (!(ind_s->size > 0 && ind_s->items[ind_s->size - 1] != 0)) { + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Indenter stack 1 top failed ne 0 check at position %zu", parser->pos); +#endif + } + } + if (parser->success) { + parse_Do(parser); + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 9))) { + if ((pgen_dispatch_mask & 0x00000000000001ffULL) != 0x00000000000001ffULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 5 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[29], 0, 0); // "minus" + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match single character "-" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 45) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "-" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + parse_SomeSpace(parser); + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (parser->success) { + parse_Exp(parser); + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 10))) { + if ((pgen_dispatch_mask & 0x00000000000003ffULL) != 0x00000000000003ffULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 4 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[28], 0, 0); // "length" + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match single character "#" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 35) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "#" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + parse_Exp(parser); + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 11))) { + if ((pgen_dispatch_mask & 0x00000000000007ffULL) != 0x00000000000007ffULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 4 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[2], 0, 0); // "bitnot" + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match single character "~" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 126) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "~" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + parse_Exp(parser); + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 12))) { + if ((pgen_dispatch_mask & 0x0000000000000fffULL) != 0x0000000000000fffULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 5 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[30], 0, 0); // "not" + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match literal "not" + if (parser->pos + 3 <= parser->input_len && + memcmp(parser->input + parser->pos, "not", 3) == 0) { + parser->pos += 3; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "not" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (parser->success) { + parse_Exp(parser); + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 13))) { + if ((pgen_dispatch_mask & 0x0000000000001fffULL) != 0x0000000000001fffULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + parse_TblComprehension(parser); + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 14))) { + if ((pgen_dispatch_mask & 0x0000000000003fffULL) != 0x0000000000003fffULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + parse_TableLit(parser); + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 15))) { + if ((pgen_dispatch_mask & 0x0000000000007fffULL) != 0x0000000000007fffULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + parse_Comprehension(parser); + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 16))) { + if ((pgen_dispatch_mask & 0x000000000000ffffULL) != 0x000000000000ffffULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + parse_FunLit(parser); + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 17))) { + if ((pgen_dispatch_mask & 0x000000000001ffffULL) != 0x000000000001ffffULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + parse_Num(parser); + } + if (!parser->success && !parser->throw_label) { + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + if (pgen_dispatch_mask != 0x000000000003ffffULL) { + // Some alternatives were skipped: replay the whole choice in original + // order so error_message reports the same failure the undispatched + // parser would. Every alternative fails, so this only affects error + // state. + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_If(parser); + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_Unless(parser); + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_Switch(parser); + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_With(parser); + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_ClassDecl(parser); + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_ForEach(parser); + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_For(parser); + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_While(parser); + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Indenter ctop (stack 1): top ne 0 + PgenIndStack *ind_s = &parser->ind_stacks[1]; + if (!(ind_s->size > 0 && ind_s->items[ind_s->size - 1] != 0)) { + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Indenter stack 1 top failed ne 0 check at position %zu", parser->pos); +#endif + } + } + if (parser->success) { + parse_Do(parser); + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 5 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[29], 0, 0); // "minus" + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match single character "-" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 45) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "-" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + parse_SomeSpace(parser); + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (parser->success) { + parse_Exp(parser); + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 4 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[28], 0, 0); // "length" + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match single character "#" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 35) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "#" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + parse_Exp(parser); + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 4 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[2], 0, 0); // "bitnot" + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match single character "~" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 126) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "~" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + parse_Exp(parser); + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 5 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[30], 0, 0); // "not" + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match literal "not" + if (parser->pos + 3 <= parser->input_len && + memcmp(parser->input + parser->pos, "not", 3) == 0) { + parser->pos += 3; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "not" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (parser->success) { + parse_Exp(parser); + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_TblComprehension(parser); + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_TableLit(parser); + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_Comprehension(parser); + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_FunLit(parser); + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_Num(parser); + } + } +#endif + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "SimpleValue", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "SimpleValue", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_SingleString(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "SingleString", start); +#endif + + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 4 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[42], 0, 0); // "string" + } + if (parser->success) { + { // Capture + size_t start_pos = parser->pos; + { // Match single character "'" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 39) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "'" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_STR, 0, start_pos, parser->pos - start_pos); + } + } + if (parser->success) { + { // Capture + size_t start_pos = parser->pos; + { // Zero or more repetitions + while (true) { + { // Choice + { // Choice + { // Match literal "\\'" + if (parser->pos + 2 <= parser->input_len && + memcmp(parser->input + parser->pos, "\\'", 2) == 0) { + parser->pos += 2; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "\\'" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Match literal "\\\\" + if (parser->pos + 2 <= parser->input_len && + memcmp(parser->input + parser->pos, "\\\\", 2) == 0) { + parser->pos += 2; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "\\\\" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match single character "'" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 39) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "'" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (parser->success) { + { // Match any 1 characters + if (parser->pos + 1 <= parser->input_len) { + parser->pos += 1; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected at least 1 more characters at position %zu", parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + } + } + if (!parser->success) { + break; + } + } + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_STR, 0, start_pos, parser->pos - start_pos); + } + } + if (parser->success) { + { // Match single character "'" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 39) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "'" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "SingleString", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "SingleString", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_Slice(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "Slice", start); +#endif + + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 9 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[39], 0, 0); // "slice" + } + if (parser->success) { + { // Match single character "[" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 91) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "[" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + { // Choice + parse_SliceValue(parser); + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[52], 0, 0); // 1 + } + } + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match single character "," + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 44) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "," + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + { // Choice + parse_SliceValue(parser); + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[0], 0, 0); // "" + } + } + } + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match single character "," + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 44) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "," + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + parse_SliceValue(parser); + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match single character "]" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 93) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "]" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + } + } + } + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "Slice", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "Slice", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_SliceValue(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "SliceValue", start); +#endif + + parse_Exp(parser); + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "SliceValue", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "SliceValue", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_SomeSpace(Parser *parser) { + size_t start = parser->pos; + // Position-pure rule (no captures, labels, or other state): a + // single-slot memo short-circuits the repeated calls that backtracking + // alternatives make at the same position + if (parser->memo[5].pos == start + 1) { + if (parser->memo[5].endpos == (size_t)-1) { + parser->success = false; + return false; + } + parser->pos = parser->memo[5].endpos; + parser->success = true; + return true; + } + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "SomeSpace", start); +#endif + + { // Sequence with 2 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + { // At least 1 repetitions + REMEMBER_INPUT_POSITION(parser, pos); + size_t rep_count = 0; + + while (true) { + { // Match character set " \t" + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 32: /* " " */ + case 9: /* "\t" */ + parser->pos++; + break; + default: +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected one of " + "\" \\t\"" + " at position %zu", + parser->pos); +#endif + parser->success = false; + } + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected one of " + "\" \\t\"" + " at position %zu but reached end of input", + parser->pos); +#endif + parser->success = false; + } + } + + if (!parser->success) { + break; + } + + rep_count += 1; + } + + // Don't recover if labeled failure was thrown + if (parser->throw_label) { + // Keep failure state, propagate labeled failure + } else if (rep_count >= 1) { + parser->success = true; + } else { + RESTORE_INPUT_POSITION(parser, pos); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected 1 repetitions at position %zu", parser->pos); +#endif + } + } + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + parse_Comment(parser); + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "SomeSpace", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "SomeSpace", parser->pos); + } +#endif + parser->memo[5].pos = start + 1; + parser->memo[5].endpos = parser->success ? parser->pos : (size_t)-1; + + parser->depth -= 1; + return parser->success; +} + +static bool parse_Space(Parser *parser) { + size_t start = parser->pos; + // Position-pure rule (no captures, labels, or other state): a + // single-slot memo short-circuits the repeated calls that backtracking + // alternatives make at the same position + if (parser->memo[6].pos == start + 1) { + if (parser->memo[6].endpos == (size_t)-1) { + parser->success = false; + return false; + } + parser->pos = parser->memo[6].endpos; + parser->success = true; + return true; + } + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "Space", start); +#endif + + { // Sequence with 2 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + { // Zero or more repetitions + while (true) { + { // Match character set " \t" + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 32: /* " " */ + case 9: /* "\t" */ + parser->pos++; + break; + default: +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected one of " + "\" \\t\"" + " at position %zu", + parser->pos); +#endif + parser->success = false; + } + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected one of " + "\" \\t\"" + " at position %zu but reached end of input", + parser->pos); +#endif + parser->success = false; + } + } + if (!parser->success) { + break; + } + } + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + } + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + parse_Comment(parser); + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "Space", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "Space", parser->pos); + } +#endif + parser->memo[6].pos = start + 1; + parser->memo[6].endpos = parser->success ? parser->pos : (size_t)-1; + + parser->depth -= 1; + return parser->success; +} + +static bool parse_SpaceBreak(Parser *parser) { + size_t start = parser->pos; + // Position-pure rule (no captures, labels, or other state): a + // single-slot memo short-circuits the repeated calls that backtracking + // alternatives make at the same position + if (parser->memo[7].pos == start + 1) { + if (parser->memo[7].endpos == (size_t)-1) { + parser->success = false; + return false; + } + parser->pos = parser->memo[7].endpos; + parser->success = true; + return true; + } + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "SpaceBreak", start); +#endif + + { // Sequence with 2 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + parse_Break(parser); + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "SpaceBreak", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "SpaceBreak", parser->pos); + } +#endif + parser->memo[7].pos = start + 1; + parser->memo[7].endpos = parser->success ? parser->pos : (size_t)-1; + + parser->depth -= 1; + return parser->success; +} + +static bool parse_Statement(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "Statement", start); +#endif + + { // Transform Capture (Cfn id=1) + size_t fn_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_FN_OPEN, __cmt_refs[1], parser->pos, 0); + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + { // Transform Capture (Cfn id=2) + size_t fn_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_FN_OPEN, __cmt_refs[2], parser->pos, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Position Capture + pgen_cap_push(parser, PGEN_CAP_POS, 0, parser->pos, 0); + } + if (parser->success) { + { // FIRST-byte dispatched ordered choice + unsigned long long pgen_dispatch_mask; + if (parser->pos < parser->input_len) { + switch ((unsigned char)parser->input[parser->pos]) { + case 105: + pgen_dispatch_mask = 0x0000000000000401ULL; + break; + case 119: + pgen_dispatch_mask = 0x0000000000000406ULL; + break; + case 102: + pgen_dispatch_mask = 0x0000000000000418ULL; + break; + case 115: + pgen_dispatch_mask = 0x0000000000000420ULL; + break; + case 114: + pgen_dispatch_mask = 0x0000000000000440ULL; + break; + case 108: + pgen_dispatch_mask = 0x0000000000000480ULL; + break; + case 101: + pgen_dispatch_mask = 0x0000000000000500ULL; + break; + case 98: + case 99: + pgen_dispatch_mask = 0x0000000000000600ULL; + break; + case 9: + case 32: + case 45: + pgen_dispatch_mask = 0x00000000000007ffULL; + break; + default: + pgen_dispatch_mask = 0x0000000000000400ULL; + break; + } + } else { + pgen_dispatch_mask = 0x0000000000000400ULL; + } + + parser->success = false; + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 0))) { + parser->success = true; + parse_Import(parser); + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 1))) { + if ((pgen_dispatch_mask & 0x0000000000000001ULL) != 0x0000000000000001ULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + parse_While(parser); + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 2))) { + if ((pgen_dispatch_mask & 0x0000000000000003ULL) != 0x0000000000000003ULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + parse_With(parser); + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 3))) { + if ((pgen_dispatch_mask & 0x0000000000000007ULL) != 0x0000000000000007ULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + parse_For(parser); + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 4))) { + if ((pgen_dispatch_mask & 0x000000000000000fULL) != 0x000000000000000fULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + parse_ForEach(parser); + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 5))) { + if ((pgen_dispatch_mask & 0x000000000000001fULL) != 0x000000000000001fULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + parse_Switch(parser); + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 6))) { + if ((pgen_dispatch_mask & 0x000000000000003fULL) != 0x000000000000003fULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + parse_Return(parser); + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 7))) { + if ((pgen_dispatch_mask & 0x000000000000007fULL) != 0x000000000000007fULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + parse_Local(parser); + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 8))) { + if ((pgen_dispatch_mask & 0x00000000000000ffULL) != 0x00000000000000ffULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + parse_Export(parser); + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 9))) { + if ((pgen_dispatch_mask & 0x00000000000001ffULL) != 0x00000000000001ffULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + parse_BreakLoop(parser); + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 10))) { + if ((pgen_dispatch_mask & 0x00000000000003ffULL) != 0x00000000000003ffULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + { // Transform Capture (Cfn id=3) + size_t fn_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_FN_OPEN, __cmt_refs[3], parser->pos, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + parse_ExpList(parser); + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + { // Choice + parse_Update(parser); + + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_Assign(parser); + } + } + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_FN_CLOSE, 0, parser->pos, 0); + } else { + parser->cap_len = fn_cap_start; + } + } + } + if (!parser->success && !parser->throw_label) { + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + if (pgen_dispatch_mask != 0x00000000000007ffULL) { + // Some alternatives were skipped: replay the whole choice in original + // order so error_message reports the same failure the undispatched + // parser would. Every alternative fails, so this only affects error + // state. + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_Import(parser); + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_While(parser); + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_With(parser); + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_For(parser); + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_ForEach(parser); + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_Switch(parser); + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_Return(parser); + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_Local(parser); + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_Export(parser); + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_BreakLoop(parser); + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Transform Capture (Cfn id=3) + size_t fn_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_FN_OPEN, __cmt_refs[3], parser->pos, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + parse_ExpList(parser); + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + { // Choice + parse_Update(parser); + + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_Assign(parser); + } + } + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_FN_CLOSE, 0, parser->pos, 0); + } else { + parser->cap_len = fn_cap_start; + } + } + } + } +#endif + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_FN_CLOSE, 0, parser->pos, 0); + } else { + parser->cap_len = fn_cap_start; + } + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Choice + { // Choice + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 7 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[23], 0, 0); // "if" + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match literal "if" + if (parser->pos + 2 <= parser->input_len && + memcmp(parser->input + parser->pos, "if", 2) == 0) { + parser->pos += 2; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "if" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (parser->success) { + parse_Exp(parser); + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + { // Sequence with 4 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match literal "else" + if (parser->pos + 4 <= parser->input_len && + memcmp(parser->input + parser->pos, "else", 4) == 0) { + parser->pos += 4; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "else" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (parser->success) { + parse_Exp(parser); + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + if (parser->success) { + parse_Space(parser); + } + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 5 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[46], 0, 0); // "unless" + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match literal "unless" + if (parser->pos + 6 <= parser->input_len && + memcmp(parser->input + parser->pos, "unless", 6) == 0) { + parser->pos += 6; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "unless" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (parser->success) { + parse_Exp(parser); + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[9], 0, 0); // "comprehension" + } + if (parser->success) { + parse_CompInner(parser); + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + } + if (parser->success) { + parse_Space(parser); + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_FN_CLOSE, 0, parser->pos, 0); + } else { + parser->cap_len = fn_cap_start; + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "Statement", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "Statement", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_Stop(Parser *parser) { + size_t start = parser->pos; + // Position-pure rule (no captures, labels, or other state): a + // single-slot memo short-circuits the repeated calls that backtracking + // alternatives make at the same position + if (parser->memo[8].pos == start + 1) { + if (parser->memo[8].endpos == (size_t)-1) { + parser->success = false; + return false; + } + parser->pos = parser->memo[8].endpos; + parser->success = true; + return true; + } + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "Stop", start); +#endif + + { // Choice + parse_Break(parser); + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match any 1 characters + if (parser->pos + 1 <= parser->input_len) { + parser->pos += 1; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected at least 1 more characters at position %zu", parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "Stop", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "Stop", parser->pos); + } +#endif + parser->memo[8].pos = start + 1; + parser->memo[8].endpos = parser->success ? parser->pos : (size_t)-1; + + parser->depth -= 1; + return parser->success; +} + +static bool parse_String(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "String", start); +#endif + + { // Choice + { // Choice + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + parse_DoubleString(parser); + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + parse_SingleString(parser); + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_LuaString(parser); + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "String", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "String", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_Switch(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "Switch", start); +#endif + + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 11 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[43], 0, 0); // "switch" + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match literal "switch" + if (parser->pos + 6 <= parser->input_len && + memcmp(parser->input + parser->pos, "switch", 6) == 0) { + parser->pos += 6; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "switch" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (parser->success) { + { // Indenter cpush (stack 1): push constant 0 + pgen_ind_push(parser, 1, 0); + } + if (parser->success) { + parse_Exp(parser); + if (parser->success) { + { // Indenter pop (stack 1) + if (!pgen_ind_pop(parser, 1)) { + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Indenter stack 1 is empty at position %zu", parser->pos); +#endif + } + } + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + { // Sequence with 3 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match literal "do" + if (parser->pos + 2 <= parser->input_len && + memcmp(parser->input + parser->pos, "do", 2) == 0) { + parser->pos += 2; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "do" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + } + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + parse_Break(parser); + if (parser->success) { + parse_SwitchBlock(parser); + } + } + } + } + } + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "Switch", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "Switch", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_SwitchBlock(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "SwitchBlock", start); +#endif + + { // Sequence with 4 patterns + REMEMBER_POSITION(parser, pos); + + { // Zero or more repetitions + while (true) { + parse_EmptyLine(parser); + if (!parser->success) { + break; + } + } + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + } + if (parser->success) { + parse_Advance(parser); + if (parser->success) { + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + parse_SwitchCase(parser); + if (parser->success) { + { // Zero or more repetitions + while (true) { + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // At least 1 repetitions + REMEMBER_INPUT_POSITION(parser, pos); + size_t rep_count = 0; + + while (true) { + parse_Break(parser); + + if (!parser->success) { + break; + } + + rep_count += 1; + } + + // Don't recover if labeled failure was thrown + if (parser->throw_label) { + // Keep failure state, propagate labeled failure + } else if (rep_count >= 1) { + parser->success = true; + } else { + RESTORE_INPUT_POSITION(parser, pos); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected 1 repetitions at position %zu", parser->pos); +#endif + } + } + if (parser->success) { + parse_SwitchCase(parser); + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + if (!parser->success) { + break; + } + } + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + } + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // At least 1 repetitions + REMEMBER_INPUT_POSITION(parser, pos); + size_t rep_count = 0; + + while (true) { + parse_Break(parser); + + if (!parser->success) { + break; + } + + rep_count += 1; + } + + // Don't recover if labeled failure was thrown + if (parser->throw_label) { + // Keep failure state, propagate labeled failure + } else if (rep_count >= 1) { + parser->success = true; + } else { + RESTORE_INPUT_POSITION(parser, pos); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected 1 repetitions at position %zu", parser->pos); +#endif + } + } + if (parser->success) { + parse_SwitchElse(parser); + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + if (parser->success) { + parse_PopIndent(parser); + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "SwitchBlock", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "SwitchBlock", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_SwitchCase(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "SwitchCase", start); +#endif + + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 7 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[5], 0, 0); // "case" + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match literal "when" + if (parser->pos + 4 <= parser->input_len && + memcmp(parser->input + parser->pos, "when", 4) == 0) { + parser->pos += 4; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "when" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (parser->success) { + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + parse_ExpList(parser); + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + { // Sequence with 3 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match literal "then" + if (parser->pos + 4 <= parser->input_len && + memcmp(parser->input + parser->pos, "then", 4) == 0) { + parser->pos += 4; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "then" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + } + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + if (parser->success) { + parse_Body(parser); + } + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "SwitchCase", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "SwitchCase", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_SwitchElse(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "SwitchElse", start); +#endif + + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 5 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[15], 0, 0); // "else" + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match literal "else" + if (parser->pos + 4 <= parser->input_len && + memcmp(parser->input + parser->pos, "else", 4) == 0) { + parser->pos += 4; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "else" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (parser->success) { + parse_Body(parser); + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "SwitchElse", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "SwitchElse", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_TableBlock(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "TableBlock", start); +#endif + + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 5 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[44], 0, 0); // "table" + } + if (parser->success) { + { // At least 1 repetitions + REMEMBER_INPUT_POSITION(parser, pos); + size_t rep_count = 0; + + while (true) { + parse_SpaceBreak(parser); + + if (!parser->success) { + break; + } + + rep_count += 1; + } + + // Don't recover if labeled failure was thrown + if (parser->throw_label) { + // Keep failure state, propagate labeled failure + } else if (rep_count >= 1) { + parser->success = true; + } else { + RESTORE_INPUT_POSITION(parser, pos); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected 1 repetitions at position %zu", parser->pos); +#endif + } + } + if (parser->success) { + parse_Advance(parser); + if (parser->success) { + parse_TableBlockInner(parser); + if (parser->success) { + parse_PopIndent(parser); + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "TableBlock", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "TableBlock", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_TableBlockInner(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "TableBlockInner", start); +#endif + + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_KeyValueLine(parser); + if (parser->success) { + { // Zero or more repetitions + while (true) { + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // At least 1 repetitions + REMEMBER_INPUT_POSITION(parser, pos); + size_t rep_count = 0; + + while (true) { + parse_SpaceBreak(parser); + + if (!parser->success) { + break; + } + + rep_count += 1; + } + + // Don't recover if labeled failure was thrown + if (parser->throw_label) { + // Keep failure state, propagate labeled failure + } else if (rep_count >= 1) { + parser->success = true; + } else { + RESTORE_INPUT_POSITION(parser, pos); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected 1 repetitions at position %zu", parser->pos); +#endif + } + } + if (parser->success) { + parse_KeyValueLine(parser); + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + if (!parser->success) { + break; + } + } + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "TableBlockInner", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "TableBlockInner", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_TableLit(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "TableLit", start); +#endif + + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 7 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[44], 0, 0); // "table" + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match single character "{" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 123) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "{" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + parse_TableValueList(parser); + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + { // Sequence with 2 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match single character "," + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 44) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "," + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + { // Sequence with 4 patterns + REMEMBER_POSITION(parser, pos); + + parse_SpaceBreak(parser); + if (parser->success) { + parse_TableLitLine(parser); + if (parser->success) { + { // Zero or more repetitions + while (true) { + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + { // Sequence with 2 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match single character "," + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 44) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "," + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + if (parser->success) { + parse_SpaceBreak(parser); + if (parser->success) { + parse_TableLitLine(parser); + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + if (!parser->success) { + break; + } + } + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + } + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + { // Sequence with 2 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match single character "," + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 44) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "," + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + if (parser->success) { + parse_White(parser); + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match single character "}" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 125) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "}" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + } + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "TableLit", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "TableLit", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_TableLitLine(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "TableLitLine", start); +#endif + + { // Choice + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + parse_PushIndent(parser); + if (parser->success) { + parse_TableValueList(parser); + if (parser->success) { + parse_PopIndent(parser); + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_Space(parser); + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "TableLitLine", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "TableLitLine", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_TableValue(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "TableValue", start); +#endif + + { // Choice + parse_KeyValue(parser); + + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + parse_Exp(parser); + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "TableValue", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "TableValue", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_TableValueList(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "TableValueList", start); +#endif + + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_TableValue(parser); + if (parser->success) { + { // Zero or more repetitions + while (true) { + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match single character "," + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 44) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "," + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + parse_TableValue(parser); + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + if (!parser->success) { + break; + } + } + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "TableValueList", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "TableValueList", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_TblComprehension(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "TblComprehension", start); +#endif + + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 7 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[45], 0, 0); // "tblcomprehension" + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match single character "{" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 123) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "{" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_Exp(parser); + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match single character "," + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 44) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "," + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + if (parser->success) { + parse_Exp(parser); + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + if (parser->success) { + parse_CompInner(parser); + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match single character "}" + if (parser->pos < parser->input_len && + parser->input[parser->pos] == 125) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character `" + "}" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + } + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "TblComprehension", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "TblComprehension", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_Unless(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "Unless", start); +#endif + + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 9 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[46], 0, 0); // "unless" + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match literal "unless" + if (parser->pos + 6 <= parser->input_len && + memcmp(parser->input + parser->pos, "unless", 6) == 0) { + parser->pos += 6; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "unless" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (parser->success) { + parse_IfCond(parser); + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + { // Sequence with 3 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match literal "then" + if (parser->pos + 4 <= parser->input_len && + memcmp(parser->input + parser->pos, "then", 4) == 0) { + parser->pos += 4; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "then" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + } + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + if (parser->success) { + parse_Body(parser); + if (parser->success) { + { // Zero or more repetitions + while (true) { + parse_IfElseIf(parser); + if (!parser->success) { + break; + } + } + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + } + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + parse_IfElse(parser); + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + } + } + } + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "Unless", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "Unless", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_Update(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "Update", start); +#endif + + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 4 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[48], 0, 0); // "update" + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Capture + size_t start_pos = parser->pos; + { // Trie match for: "..=", "+=", "-=", "*=", "\/=", "%=", "or=", "and=", "&=", "|=", ">>=", "<<=" + REMEMBER_POSITION(parser, trie_start); + size_t last_terminal_pos = 0; + int has_terminal = 0; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 37: // "%" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 61: // "=" + parser->pos++; + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + case 38: // "&" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 61: // "=" + parser->pos++; + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + case 42: // "*" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 61: // "=" + parser->pos++; + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + case 43: // "+" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 61: // "=" + parser->pos++; + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + case 45: // "-" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 61: // "=" + parser->pos++; + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + case 46: // "." + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 46: // "." + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 61: // "=" + parser->pos++; + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + case 47: // "/" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 61: // "=" + parser->pos++; + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + case 60: // "<" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 60: // "<" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 61: // "=" + parser->pos++; + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + case 62: // ">" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 62: // ">" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 61: // "=" + parser->pos++; + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + case 97: // "a" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 110: // "n" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 100: // "d" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 61: // "=" + parser->pos++; + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + case 111: // "o" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 114: // "r" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 61: // "=" + parser->pos++; + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + case 124: // "|" + parser->pos++; + + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 61: // "=" + parser->pos++; + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + break; + default: + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + } else { + parser->success = false; + if (has_terminal) { + parser->pos = last_terminal_pos; + parser->success = true; + } else { + PGEN_RECORD_FURTHEST(parser); + } + } + if (!parser->success) { + RESTORE_POSITION(parser, trie_start); + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_STR, 0, start_pos, parser->pos - start_pos); + } + } + if (parser->success) { + parse_Exp(parser); + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "Update", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "Update", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_Value(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "Value", start); +#endif + + { // Transform Capture (Cfn id=2) + size_t fn_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_FN_OPEN, __cmt_refs[2], parser->pos, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Position Capture + pgen_cap_push(parser, PGEN_CAP_POS, 0, parser->pos, 0); + } + if (parser->success) { + { // FIRST-byte dispatched ordered choice + unsigned long long pgen_dispatch_mask; + if (parser->pos < parser->input_len) { + switch ((unsigned char)parser->input[parser->pos]) { + case 58: + case 64: + case 65: + case 66: + case 67: + case 68: + case 69: + case 70: + case 71: + case 72: + case 73: + case 74: + case 75: + case 76: + case 77: + case 78: + case 79: + case 80: + case 81: + case 82: + case 83: + case 84: + case 85: + case 86: + case 87: + case 88: + case 89: + case 90: + case 95: + case 97: + case 98: + case 99: + case 100: + case 101: + case 102: + case 103: + case 104: + case 105: + case 106: + case 107: + case 108: + case 109: + case 110: + case 111: + case 112: + case 113: + case 114: + case 115: + case 116: + case 117: + case 118: + case 119: + case 120: + case 121: + case 122: + pgen_dispatch_mask = 0x0000000000000007ULL; + break; + case 9: + case 32: + case 34: + case 39: + case 45: + case 91: + pgen_dispatch_mask = 0x000000000000000fULL; + break; + default: + pgen_dispatch_mask = 0x0000000000000005ULL; + break; + } + } else { + pgen_dispatch_mask = 0x0000000000000005ULL; + } + + parser->success = false; + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 0))) { + parser->success = true; + parse_SimpleValue(parser); + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 1))) { + if ((pgen_dispatch_mask & 0x0000000000000001ULL) != 0x0000000000000001ULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[44], 0, 0); // "table" + } + if (parser->success) { + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + parse_KeyValueList(parser); + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 2))) { + if ((pgen_dispatch_mask & 0x0000000000000003ULL) != 0x0000000000000003ULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + parse_ChainValue(parser); + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 3))) { + if ((pgen_dispatch_mask & 0x0000000000000007ULL) != 0x0000000000000007ULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + parse_String(parser); + } + if (!parser->success && !parser->throw_label) { + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + if (pgen_dispatch_mask != 0x000000000000000fULL) { + // Some alternatives were skipped: replay the whole choice in original + // order so error_message reports the same failure the undispatched + // parser would. Every alternative fails, so this only affects error + // state. + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_SimpleValue(parser); + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[44], 0, 0); // "table" + } + if (parser->success) { + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + parse_KeyValueList(parser); + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_ChainValue(parser); + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + parse_String(parser); + } + } +#endif + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_FN_CLOSE, 0, parser->pos, 0); + } else { + parser->cap_len = fn_cap_start; + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "Value", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "Value", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_VarArg(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "VarArg", start); +#endif + + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Capture + size_t start_pos = parser->pos; + { // Match literal "..." + if (parser->pos + 3 <= parser->input_len && + memcmp(parser->input + parser->pos, "...", 3) == 0) { + parser->pos += 3; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "..." + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_STR, 0, start_pos, parser->pos - start_pos); + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "VarArg", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "VarArg", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_While(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "While", start); +#endif + + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 9 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[50], 0, 0); // "while" + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match literal "while" + if (parser->pos + 5 <= parser->input_len && + memcmp(parser->input + parser->pos, "while", 5) == 0) { + parser->pos += 5; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "while" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (parser->success) { + { // Indenter cpush (stack 1): push constant 0 + pgen_ind_push(parser, 1, 0); + } + if (parser->success) { + parse_Exp(parser); + if (parser->success) { + { // Indenter pop (stack 1) + if (!pgen_ind_pop(parser, 1)) { + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Indenter stack 1 is empty at position %zu", parser->pos); +#endif + } + } + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + { // Sequence with 3 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match literal "do" + if (parser->pos + 2 <= parser->input_len && + memcmp(parser->input + parser->pos, "do", 2) == 0) { + parser->pos += 2; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "do" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + } + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + if (parser->success) { + parse_Body(parser); + } + } + } + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "While", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "While", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_White(Parser *parser) { + size_t start = parser->pos; + // Position-pure rule (no captures, labels, or other state): a + // single-slot memo short-circuits the repeated calls that backtracking + // alternatives make at the same position + if (parser->memo[9].pos == start + 1) { + if (parser->memo[9].endpos == (size_t)-1) { + parser->success = false; + return false; + } + parser->pos = parser->memo[9].endpos; + parser->success = true; + return true; + } + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "White", start); +#endif + + { // Zero or more repetitions + while (true) { + { // Match character set " \t\r\n" + if (parser->pos < parser->input_len) { + switch (parser->input[parser->pos]) { + case 32: /* " " */ + case 9: /* "\t" */ + case 13: /* "\r" */ + case 10: /* "\n" */ + parser->pos++; + break; + default: +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected one of " + "\" \\t\\r\\n\"" + " at position %zu", + parser->pos); +#endif + parser->success = false; + } + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected one of " + "\" \\t\\r\\n\"" + " at position %zu but reached end of input", + parser->pos); +#endif + parser->success = false; + } + } + if (!parser->success) { + break; + } + } + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "White", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "White", parser->pos); + } +#endif + parser->memo[9].pos = start + 1; + parser->memo[9].endpos = parser->success ? parser->pos : (size_t)-1; + + parser->depth -= 1; + return parser->success; +} + +static bool parse_With(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "With", start); +#endif + + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + { // Sequence with 9 patterns + REMEMBER_POSITION(parser, pos); + + { // Constant Capture + // A constant capture matches the empty string and produces all given values + pgen_cap_push(parser, PGEN_CAP_CONST, __const_refs[51], 0, 0); // "with" + } + if (parser->success) { + parse_Space(parser); + if (parser->success) { + { // Match literal "with" + if (parser->pos + 4 <= parser->input_len && + memcmp(parser->input + parser->pos, "with", 4) == 0) { + parser->pos += 4; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "with" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + if (parser->success) { + { // Indenter cpush (stack 1): push constant 0 + pgen_ind_push(parser, 1, 0); + } + if (parser->success) { + parse_WithExp(parser); + if (parser->success) { + { // Indenter pop (stack 1) + if (!pgen_ind_pop(parser, 1)) { + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Indenter stack 1 is empty at position %zu", parser->pos); +#endif + } + } + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + { // Sequence with 3 patterns + REMEMBER_INPUT_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Match literal "do" + if (parser->pos + 2 <= parser->input_len && + memcmp(parser->input + parser->pos, "do", 2) == 0) { + parser->pos += 2; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "do" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + } + if (!parser->success) { + RESTORE_INPUT_POSITION(parser, pos); + } + } + } + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + if (parser->success) { + parse_Body(parser); + } + } + } + } + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "With", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "With", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_WithExp(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "WithExp", start); +#endif + + { // Transform Capture (Cfn id=3) + size_t fn_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_FN_OPEN, __cmt_refs[3], parser->pos, 0); + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + { // Capture Table + size_t ct_cap_start = parser->cap_len; + pgen_cap_push(parser, PGEN_CAP_TBL_OPEN, 0, 0, 0); + parse_ExpList(parser); + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_TBL_CLOSE, 0, 0, 0); + } else { + parser->cap_len = ct_cap_start; + } + } + if (parser->success) { + { // At most 1 repetitions + size_t rep_count = 0; + + while (rep_count < 1) { + size_t before_pos = parser->pos; + + { + parse_Assign(parser); + } + + if (!parser->success || before_pos == parser->pos) { + // Break on failure or zero-width match + // Only recover from ordinary failure, not labeled failure from T() + if (!parser->throw_label) { + parser->success = true; + } + break; + } + + rep_count += 1; + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_FN_CLOSE, 0, parser->pos, 0); + } else { + parser->cap_len = fn_cap_start; + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "WithExp", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "WithExp", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +static bool parse_WordOperators(Parser *parser) { + size_t start = parser->pos; + + parser->depth += 1; + if (parser->depth > PGEN_MAX_DEPTH) { + // A Lua error (rather than a match failure) so the overflow can't be + // silently converted into a successful parse by a predicate or choice + luaL_error(parser->L, "pgen: max recursion depth (%d) exceeded at position %d", (int)PGEN_MAX_DEPTH, (int)(parser->pos + 1)); + } + +#ifdef PGEN_DEBUG + fprintf(stderr, "%*sEntering rule %s at position %zu\n", (int)parser->depth, "", "WordOperators", start); +#endif + + { // FIRST-byte dispatched ordered choice + unsigned long long pgen_dispatch_mask; + if (parser->pos < parser->input_len) { + switch ((unsigned char)parser->input[parser->pos]) { + case 111: + pgen_dispatch_mask = 0x0000000000000001ULL; + break; + case 97: + pgen_dispatch_mask = 0x0000000000000002ULL; + break; + case 126: + pgen_dispatch_mask = 0x0000000000000010ULL; + break; + case 33: + pgen_dispatch_mask = 0x0000000000000020ULL; + break; + case 61: + pgen_dispatch_mask = 0x0000000000000040ULL; + break; + case 46: + pgen_dispatch_mask = 0x0000000000000080ULL; + break; + case 60: + pgen_dispatch_mask = 0x0000000000000104ULL; + break; + case 62: + pgen_dispatch_mask = 0x0000000000000208ULL; + break; + case 47: + pgen_dispatch_mask = 0x0000000000000400ULL; + break; + case 9: + case 32: + case 45: + pgen_dispatch_mask = 0x00000000000007ffULL; + break; + default: + pgen_dispatch_mask = 0x0000000000000000ULL; + break; + } + } else { + pgen_dispatch_mask = 0x0000000000000000ULL; + } + + parser->success = false; + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 0))) { + parser->success = true; + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Capture + size_t start_pos = parser->pos; + { // Match literal "or" + if (parser->pos + 2 <= parser->input_len && + memcmp(parser->input + parser->pos, "or", 2) == 0) { + parser->pos += 2; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "or" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_STR, 0, start_pos, parser->pos - start_pos); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 1))) { + if ((pgen_dispatch_mask & 0x0000000000000001ULL) != 0x0000000000000001ULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Capture + size_t start_pos = parser->pos; + { // Match literal "and" + if (parser->pos + 3 <= parser->input_len && + memcmp(parser->input + parser->pos, "and", 3) == 0) { + parser->pos += 3; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "and" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_STR, 0, start_pos, parser->pos - start_pos); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 2))) { + if ((pgen_dispatch_mask & 0x0000000000000003ULL) != 0x0000000000000003ULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Capture + size_t start_pos = parser->pos; + { // Match literal "<=" + if (parser->pos + 2 <= parser->input_len && + memcmp(parser->input + parser->pos, "<=", 2) == 0) { + parser->pos += 2; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "<=" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_STR, 0, start_pos, parser->pos - start_pos); + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 3))) { + if ((pgen_dispatch_mask & 0x0000000000000007ULL) != 0x0000000000000007ULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Capture + size_t start_pos = parser->pos; + { // Match literal ">=" + if (parser->pos + 2 <= parser->input_len && + memcmp(parser->input + parser->pos, ">=", 2) == 0) { + parser->pos += 2; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + ">=" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_STR, 0, start_pos, parser->pos - start_pos); + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 4))) { + if ((pgen_dispatch_mask & 0x000000000000000fULL) != 0x000000000000000fULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Capture + size_t start_pos = parser->pos; + { // Match literal "~=" + if (parser->pos + 2 <= parser->input_len && + memcmp(parser->input + parser->pos, "~=", 2) == 0) { + parser->pos += 2; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "~=" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_STR, 0, start_pos, parser->pos - start_pos); + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 5))) { + if ((pgen_dispatch_mask & 0x000000000000001fULL) != 0x000000000000001fULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Capture + size_t start_pos = parser->pos; + { // Match literal "!=" + if (parser->pos + 2 <= parser->input_len && + memcmp(parser->input + parser->pos, "!=", 2) == 0) { + parser->pos += 2; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "!=" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_STR, 0, start_pos, parser->pos - start_pos); + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 6))) { + if ((pgen_dispatch_mask & 0x000000000000003fULL) != 0x000000000000003fULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Capture + size_t start_pos = parser->pos; + { // Match literal "==" + if (parser->pos + 2 <= parser->input_len && + memcmp(parser->input + parser->pos, "==", 2) == 0) { + parser->pos += 2; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "==" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_STR, 0, start_pos, parser->pos - start_pos); + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 7))) { + if ((pgen_dispatch_mask & 0x000000000000007fULL) != 0x000000000000007fULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Capture + size_t start_pos = parser->pos; + { // Match literal ".." + if (parser->pos + 2 <= parser->input_len && + memcmp(parser->input + parser->pos, "..", 2) == 0) { + parser->pos += 2; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + ".." + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_STR, 0, start_pos, parser->pos - start_pos); + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 8))) { + if ((pgen_dispatch_mask & 0x00000000000000ffULL) != 0x00000000000000ffULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Capture + size_t start_pos = parser->pos; + { // Match literal "<<" + if (parser->pos + 2 <= parser->input_len && + memcmp(parser->input + parser->pos, "<<", 2) == 0) { + parser->pos += 2; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "<<" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_STR, 0, start_pos, parser->pos - start_pos); + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 9))) { + if ((pgen_dispatch_mask & 0x00000000000001ffULL) != 0x00000000000001ffULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Capture + size_t start_pos = parser->pos; + { // Match literal ">>" + if (parser->pos + 2 <= parser->input_len && + memcmp(parser->input + parser->pos, ">>", 2) == 0) { + parser->pos += 2; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + ">>" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_STR, 0, start_pos, parser->pos - start_pos); + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + if (!parser->success && !parser->throw_label && (pgen_dispatch_mask & (1ULL << 10))) { + if ((pgen_dispatch_mask & 0x00000000000003ffULL) != 0x00000000000003ffULL) { + PGEN_RECORD_FURTHEST(parser); + } + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Capture + size_t start_pos = parser->pos; + { // Match literal "\/\/" + if (parser->pos + 2 <= parser->input_len && + memcmp(parser->input + parser->pos, "//", 2) == 0) { + parser->pos += 2; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "//" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_STR, 0, start_pos, parser->pos - start_pos); + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + if (!parser->success && !parser->throw_label) { + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + if (pgen_dispatch_mask != 0x00000000000007ffULL) { + // Some alternatives were skipped: replay the whole choice in original + // order so error_message reports the same failure the undispatched + // parser would. Every alternative fails, so this only affects error + // state. + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Capture + size_t start_pos = parser->pos; + { // Match literal "or" + if (parser->pos + 2 <= parser->input_len && + memcmp(parser->input + parser->pos, "or", 2) == 0) { + parser->pos += 2; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "or" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_STR, 0, start_pos, parser->pos - start_pos); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Sequence with 3 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Capture + size_t start_pos = parser->pos; + { // Match literal "and" + if (parser->pos + 3 <= parser->input_len && + memcmp(parser->input + parser->pos, "and", 3) == 0) { + parser->pos += 3; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "and" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_STR, 0, start_pos, parser->pos - start_pos); + } + } + if (parser->success) { + { // Negate (only match if pattern fails) + REMEMBER_INPUT_POSITION(parser, pos); + + { // Match character range: "az,AZ,09,__" + if (parser->pos < parser->input_len && + ((parser->input[parser->pos] >= 97 && parser->input[parser->pos] <= 122) || (parser->input[parser->pos] >= 65 && parser->input[parser->pos] <= 90) || (parser->input[parser->pos] >= 48 && parser->input[parser->pos] <= 57) || (parser->input[parser->pos] >= 95 && parser->input[parser->pos] <= 95))) { + parser->pos++; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected character in ranges [" + "a" + " - " + "z" + ", " + "A" + " - " + "Z" + ", " + "0" + " - " + "9" + ", " + "_" + " - " + "_" + "] at position %zu", + parser->pos); +#endif + parser->success = false; + } + } + + if (parser->success) { + // Pattern matched, so negate fails + RESTORE_INPUT_POSITION(parser, pos); + parser->success = false; + PGEN_RECORD_FURTHEST(parser); +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Negated pattern unexpectedly matched at position %zu", pos.pos); +#endif + } else { + // Pattern failed, so negate succeeds + parser->success = true; + // Swallow labeled failures inside predicates (LPegLabel behavior) + if (parser->throw_label) { + parser->throw_label = NULL; + parser->throw_pos = 0; + } + RESTORE_INPUT_POSITION(parser, pos); // Restore original position (technically not necessary since failed pattern should make no changes to position) + } + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Capture + size_t start_pos = parser->pos; + { // Match literal "<=" + if (parser->pos + 2 <= parser->input_len && + memcmp(parser->input + parser->pos, "<=", 2) == 0) { + parser->pos += 2; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "<=" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_STR, 0, start_pos, parser->pos - start_pos); + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Capture + size_t start_pos = parser->pos; + { // Match literal ">=" + if (parser->pos + 2 <= parser->input_len && + memcmp(parser->input + parser->pos, ">=", 2) == 0) { + parser->pos += 2; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + ">=" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_STR, 0, start_pos, parser->pos - start_pos); + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Capture + size_t start_pos = parser->pos; + { // Match literal "~=" + if (parser->pos + 2 <= parser->input_len && + memcmp(parser->input + parser->pos, "~=", 2) == 0) { + parser->pos += 2; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "~=" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_STR, 0, start_pos, parser->pos - start_pos); + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Capture + size_t start_pos = parser->pos; + { // Match literal "!=" + if (parser->pos + 2 <= parser->input_len && + memcmp(parser->input + parser->pos, "!=", 2) == 0) { + parser->pos += 2; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "!=" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_STR, 0, start_pos, parser->pos - start_pos); + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Capture + size_t start_pos = parser->pos; + { // Match literal "==" + if (parser->pos + 2 <= parser->input_len && + memcmp(parser->input + parser->pos, "==", 2) == 0) { + parser->pos += 2; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "==" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_STR, 0, start_pos, parser->pos - start_pos); + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Capture + size_t start_pos = parser->pos; + { // Match literal ".." + if (parser->pos + 2 <= parser->input_len && + memcmp(parser->input + parser->pos, "..", 2) == 0) { + parser->pos += 2; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + ".." + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_STR, 0, start_pos, parser->pos - start_pos); + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Capture + size_t start_pos = parser->pos; + { // Match literal "<<" + if (parser->pos + 2 <= parser->input_len && + memcmp(parser->input + parser->pos, "<<", 2) == 0) { + parser->pos += 2; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "<<" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_STR, 0, start_pos, parser->pos - start_pos); + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Capture + size_t start_pos = parser->pos; + { // Match literal ">>" + if (parser->pos + 2 <= parser->input_len && + memcmp(parser->input + parser->pos, ">>", 2) == 0) { + parser->pos += 2; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + ">>" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_STR, 0, start_pos, parser->pos - start_pos); + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + if (!parser->success && !parser->throw_label) { + parser->success = true; + { // Sequence with 2 patterns + REMEMBER_POSITION(parser, pos); + + parse_Space(parser); + if (parser->success) { + { // Capture + size_t start_pos = parser->pos; + { // Match literal "\/\/" + if (parser->pos + 2 <= parser->input_len && + memcmp(parser->input + parser->pos, "//", 2) == 0) { + parser->pos += 2; + } else { +#ifdef PGEN_ERRORS + sprintf(parser->error_message, "Expected `" + "//" + "` at position %zu", + parser->pos); +#endif + parser->success = false; + PGEN_RECORD_FURTHEST(parser); + } + } + + if (parser->success) { + pgen_cap_push(parser, PGEN_CAP_STR, 0, start_pos, parser->pos - start_pos); + } + } + if (!parser->success) { + RESTORE_POSITION(parser, pos); + } + } + } + } + } +#endif + } + } + +#ifdef PGEN_DEBUG + if (parser->success) { + fprintf(stderr, "%*sRule %s matched range: %zu-%zu\n", (int)parser->depth, "", "WordOperators", start, parser->pos); + fprintf(stderr, "%*s\t%.*s\n", (int)parser->depth, "", (int)(parser->pos - start), parser->input + start); + } else { + fprintf(stderr, "%*sRule %s failed at position %zu\n", (int)parser->depth, "", "WordOperators", parser->pos); + } +#endif + + parser->depth -= 1; + return parser->success; +} + +#define PGEN_PARSER_MT "pgen.moonscript_parse_native" + +// Initialize a parser anchored in a Lua userdata (left on the stack). Its +// metatable's __gc frees the owned allocations, so a Lua error unwinding +// out of a parse (transform/Cmt callbacks, recursion depth, out of memory) +// cannot leak them. +static Parser *moonscript_parse_native_init(const char *input, lua_State *L) { + Parser *parser = (Parser *)lua_newuserdata(L, sizeof(Parser)); + + // Null the owned pointers before attaching the metatable so __gc is + // safe even if a later allocation fails mid-init + parser->caps = NULL; + parser->trail = NULL; + parser->trail_len = 0; + parser->trail_cap = 0; + for (int i = 0; i < PGEN_IND_STACK_COUNT; i++) { + parser->ind_stacks[i].items = NULL; + } + luaL_getmetatable(L, PGEN_PARSER_MT); + lua_setmetatable(L, -2); + + parser->input = input; + parser->input_len = strlen(input); + parser->pos = 0; + parser->depth = 0; + parser->success = true; + parser->error_message[0] = '\0'; + parser->throw_label = NULL; + parser->throw_pos = 0; + parser->furthest_fail = 0; + parser->top = lua_gettop(L); + parser->stack_claimed = parser->top; + parser->L = L; + + parser->caps = (PgenCap *)malloc(64 * sizeof(PgenCap)); + if (!parser->caps) { + luaL_error(L, "pgen: out of memory initializing parser"); + } + parser->cap_len = 0; + parser->cap_cap = 64; + for (int i = 0; i < PGEN_MEMO_COUNT; i++) { + parser->memo[i].pos = 0; // empty slot + } + + // Initialize indenter stacks (each starts holding its initial value) + static const int pgen_ind_initials[PGEN_IND_STACK_COUNT] = {0, 1}; + for (int i = 0; i < PGEN_IND_STACK_COUNT; i++) { + parser->ind_stacks[i].items = (int *)malloc(8 * sizeof(int)); + if (!parser->ind_stacks[i].items) { + luaL_error(L, "pgen: out of memory initializing parser"); + } + parser->ind_stacks[i].cap = 8; + parser->ind_stacks[i].size = 1; + parser->ind_stacks[i].items[0] = pgen_ind_initials[i]; + } + + return parser; +} + +// Free the parser's owned allocations. Idempotent: called eagerly on +// normal completion and again from __gc, which also covers error unwinds +static void moonscript_parse_native_free(Parser *parser) { + if (parser) { + for (int i = 0; i < PGEN_IND_STACK_COUNT; i++) { + free(parser->ind_stacks[i].items); + parser->ind_stacks[i].items = NULL; + } + free(parser->trail); + parser->trail = NULL; + free(parser->caps); + parser->caps = NULL; + } +} + +// --- Lua Module Interface --- + +// __gc for the parser userdata: frees whatever the eager free didn't +static int l_moonscript_parse_native_gc(lua_State *L) { + moonscript_parse_native_free((Parser *)lua_touserdata(L, 1)); + return 0; +} + +// Lua wrapper function +static int l_moonscript_parse_native_parse(lua_State *L) { + // Check type and get the input string + if (!lua_isstring(L, 1)) { + return luaL_error(L, "Expected string argument for parsing"); + } + const char *input = lua_tostring(L, 1); + if (!input) { + // Should not happen if lua_isstring passed, but good practice + return luaL_error(L, "Failed to get string argument"); + } + + // Initialize the parser (a userdata anchored on the stack; see _init) + Parser *parser = moonscript_parse_native_init(input, L); + + int initial_stack_size = lua_gettop(parser->L); + + parse_Root(parser); + + int final_stack_size = lua_gettop(parser->L); + assert(parser->top == final_stack_size && "Shadow stack top out of sync."); + + // Return nil and error info on failure + if (!parser->success) { + assert(final_stack_size == initial_stack_size && "Unexpected stack size change on parse failure."); + assert(parser->cap_len == 0 && "Capture log not empty on parse failure."); + lua_pushnil(L); + if (parser->throw_label) { + // Labeled failure: return nil, label, position + lua_pushstring(L, parser->throw_label); + lua_pushinteger(L, parser->throw_pos + 1); // 1-indexed for Lua + moonscript_parse_native_free(parser); + return 3; + } else { + // Ordinary failure: return nil, message (PGEN_ERRORS builds only) and + // the furthest input position a match attempt failed at (1-indexed) +#ifdef PGEN_ERRORS + lua_pushstring(L, parser->error_message); +#else + lua_pushnil(L); +#endif + lua_pushinteger(L, parser->furthest_fail + 1); + moonscript_parse_native_free(parser); + return 3; + } + } + + // Materialize the capture log into return values. Named groups produce + // no top-level values (they only matter inside Ct). + int cmt_slots = parser->top - initial_stack_size; // lingering Cmt values + int result_count = 0; + size_t cap_i = 0; + while (cap_i < parser->cap_len) { + if (parser->caps[cap_i].kind == PGEN_CAP_GROUP_OPEN) { + pgen_cap_skip(parser, &cap_i); + } else { + result_count += pgen_cap_eval(parser, &cap_i); + } + } + + // Drop the lingering Cmt value slots sitting beneath the results + for (int i = 0; i < cmt_slots; i++) { + lua_remove(L, initial_stack_size + 1); + } + + if (result_count > 0) { + moonscript_parse_native_free(parser); + return result_count; + } + + // Success case with no captures + lua_pushinteger(L, parser->pos + 1); + moonscript_parse_native_free(parser); + return 1; // Return position of consumed input +} + +// Lua module function registration table +static const struct luaL_Reg moonscript_parse_native_module[] = { + {"parse", l_moonscript_parse_native_parse}, // Expose l_parsername_parse as "parse" in Lua + {NULL, NULL} // Sentinel +}; + +// Lua module entry point (compatible with Lua 5.1+) +// Note: LUA_VERSION_NUM wasn't defined before 5.1 +#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM >= 502 +// Lua 5.2+ uses luaL_setfuncs +int luaopen_moonscript_parse_native(lua_State *L) { + if (luaL_newmetatable(L, PGEN_PARSER_MT)) { + lua_pushcfunction(L, l_moonscript_parse_native_gc); + lua_setfield(L, -2, "__gc"); + } + lua_pop(L, 1); + __const_init(L); + __cmt_init(L); + luaL_newlib(L, moonscript_parse_native_module); // Creates table and registers functions + return 1; +} +#else +// Lua 5.1 uses luaL_register. Register into a fresh table rather than a +// named global: a name would be shared through package.loaded, so loading +// two parsers compiled with the same parser_name in one process would +// silently overwrite the first module's parse function. +int luaopen_moonscript_parse_native(lua_State *L) { + if (luaL_newmetatable(L, PGEN_PARSER_MT)) { + lua_pushcfunction(L, l_moonscript_parse_native_gc); + lua_setfield(L, -2, "__gc"); + } + lua_pop(L, 1); + __const_init(L); + __cmt_init(L); + lua_newtable(L); + luaL_register(L, NULL, moonscript_parse_native_module); + return 1; +} +#endif + +/* +To compile as a Lua module: +gcc -shared -o moonscript_parse_native.so -fPIC moonscript_parse_native.c `pkg-config --cflags --libs lua5.1` + +To use in Lua: +local moonscript_parse_native = require "moonscript_parse_native" +local result = moonscript_parse_native.parse("your input string") +*/ diff --git a/moonscript/parse/slow.lua b/moonscript/parse/slow.lua new file mode 100644 index 00000000..b210e02c --- /dev/null +++ b/moonscript/parse/slow.lua @@ -0,0 +1,13560 @@ +-- Generated by pgen 0.1.0 (Lua target) +-- moonscript_parse_slow - generated parser +-- +-- Self-contained pure Lua module (Lua 5.1+ and LuaJIT), no dependencies. +-- local moonscript_parse_slow = require "moonscript_parse_slow" +-- local result = moonscript_parse_slow.parse("your input string") + +local select, type, error, pcall, tostring = select, type, error, pcall, tostring +local byte, sub = string.byte, string.sub +local unpack = table.unpack or unpack +local pack = table.pack or function(...) return {n = select("#", ...), ...} end + +-- Maximum rule-call recursion depth before the parse is aborted with a Lua +-- error (catch with pcall). Configure with the max_depth compile option. +local MAX_DEPTH = 5000 + +-- Capture log entry kinds. Captures are recorded as log entries during +-- matching and only materialized into Lua values after the whole parse +-- succeeds; backtracking rewinds the log length, so discarded speculative +-- captures are never built. The exception is Cmt: its callback runs +-- mid-parse and its extra return values are stored in the parser's values +-- array, referenced by CAP_VALUE entries. +local CAP_STR, CAP_CONST, CAP_NIL, CAP_POS, CAP_VALUE = 1, 2, 3, 4, 5 +local CAP_TBL_OPEN, CAP_TBL_CLOSE = 6, 7 +local CAP_GROUP_OPEN, CAP_GROUP_CLOSE = 8, 9 +local CAP_FN_OPEN, CAP_FN_CLOSE = 10, 11 + +local rules = {} +local sets = {} +local disp = {} +local cmt_fns = {} +-- Sentinel pushed by `prevent`: no measured width compares greater +local IND_PREVENT = math.huge + +-- Records the furthest input position where a match attempt failed (only +-- ever increases); parse() reports it when the overall parse fails without +-- a label. Not recorded in single-character matchers, mirroring the C +-- target. +local function record_furthest(parser) + if parser.pos > parser.furthest_fail then + parser.furthest_fail = parser.pos + end +end + +-- Append one capture log entry (parallel arrays, truncated by cap_n rewinds) +local function cap_push(parser, kind, aux, start, len) + local n = parser.cap_n + 1 + parser.cap_n = n + parser.cap_kind[n] = kind + parser.cap_aux[n] = aux + parser.cap_start[n] = start + parser.cap_size[n] = len +end + +-- Advance past one complete log item (a single entry, or a whole bracketed +-- range including anything nested), returning the index after it +local function cap_skip(parser, i) + local ck = parser.cap_kind + local kind = ck[i] + i = i + 1 + if kind == CAP_TBL_OPEN or kind == CAP_GROUP_OPEN or kind == CAP_FN_OPEN then + local depth = 1 + while depth > 0 do + kind = ck[i] + if kind == CAP_TBL_OPEN or kind == CAP_GROUP_OPEN or kind == CAP_FN_OPEN then + depth = depth + 1 + elseif kind == CAP_TBL_CLOSE or kind == CAP_GROUP_CLOSE or kind == CAP_FN_CLOSE then + depth = depth - 1 + end + i = i + 1 + end + end + return i +end + +local cap_eval + +-- Append the single value a capture group produces to out: its first inner +-- capture value, or the text it matched when its contents produce no values. +-- Returns the index past the group's close entry. +local function cap_eval_group(parser, i, out) + local open = i + local after = cap_skip(parser, i) + local close = after - 1 + + local j = open + 1 + while j < close do + local before_n = out.n + j = cap_eval(parser, j, out) + if out.n > before_n then + -- keep only the first value + for k = before_n + 2, out.n do out[k] = nil end + out.n = before_n + 1 + return after + end + end + + -- no values: the group's value is the text it matched + local start = parser.cap_start[open] + out.n = out.n + 1 + out[out.n] = sub(parser.input, start + 1, parser.cap_start[close]) + return after +end + +-- Materialize one log item (entry or bracketed range) at i, appending its +-- values to out (out.n counts values so nil captures are preserved). +-- Returns the index past the item. Runs once after a successful parse (and +-- on demand at Cmt boundaries), so it is not on the matching hot path. +function cap_eval(parser, i, out) + local ck = parser.cap_kind + local kind = ck[i] + if kind == CAP_STR then + local start = parser.cap_start[i] + out.n = out.n + 1 + out[out.n] = sub(parser.input, start + 1, start + parser.cap_size[i]) + return i + 1 + elseif kind == CAP_CONST then + out.n = out.n + 1 + out[out.n] = parser.cap_aux[i] + return i + 1 + elseif kind == CAP_NIL then + out.n = out.n + 1 + out[out.n] = nil + return i + 1 + elseif kind == CAP_POS then + out.n = out.n + 1 + out[out.n] = parser.cap_start[i] + 1 + return i + 1 + elseif kind == CAP_VALUE then + out.n = out.n + 1 + out[out.n] = parser.values[parser.cap_aux[i]] + return i + 1 + elseif kind == CAP_GROUP_OPEN then + return cap_eval_group(parser, i, out) + elseif kind == CAP_FN_OPEN then + -- Transform capture: inner values become arguments, the callback's + -- return values become the capture values (innermost-first order falls + -- out of the recursion here) + local open = i + local fn = parser.cap_aux[i] + local args = {n = 0} + local j = open + 1 + while ck[j] ~= CAP_FN_CLOSE do + if ck[j] == CAP_GROUP_OPEN then + -- named groups are not visible as arguments (as at the top level) + j = cap_skip(parser, j) + else + j = cap_eval(parser, j, args) + end + end + if args.n == 0 then + -- no inner captures: the callback receives the matched text + local start = parser.cap_start[open] + args[1] = sub(parser.input, start + 1, parser.cap_start[j]) + args.n = 1 + end + -- callback errors propagate (abort materialization with the original + -- error value) + local rets = pack(fn(unpack(args, 1, args.n))) + for k = 1, rets.n do + out.n = out.n + 1 + out[out.n] = rets[k] + end + return j + 1 + else -- CAP_TBL_OPEN + local tbl = {} + local j = i + 1 + local array_idx = 1 + local item = {n = 0} + while ck[j] ~= CAP_TBL_CLOSE do + if ck[j] == CAP_GROUP_OPEN then + local group_name = parser.cap_aux[j] + item.n = 0 + j = cap_eval_group(parser, j, item) + tbl[group_name] = item[1] + else + item.n = 0 + j = cap_eval(parser, j, item) + for k = 1, item.n do + tbl[array_idx] = item[k] + array_idx = array_idx + 1 + end + end + end + out.n = out.n + 1 + out[out.n] = tbl + return j + 1 + end +end + +-- Match the text of the most recent visible named capture group at the +-- current input position. Groups inside completed capture tables are not +-- visible. +local function cap_match_back(parser, name) + local ck, ca = parser.cap_kind, parser.cap_aux + local cs, cz = parser.cap_start, parser.cap_size + local i = parser.cap_n + while i >= 1 do + local kind = ck[i] + if kind == CAP_TBL_CLOSE or kind == CAP_GROUP_CLOSE or kind == CAP_FN_CLOSE then + local close = i + local depth = 1 + while depth > 0 do + i = i - 1 + local k2 = ck[i] + if k2 == CAP_TBL_CLOSE or k2 == CAP_GROUP_CLOSE or k2 == CAP_FN_CLOSE then + depth = depth + 1 + elseif k2 == CAP_TBL_OPEN or k2 == CAP_GROUP_OPEN or k2 == CAP_FN_OPEN then + depth = depth - 1 + end + end + if kind == CAP_GROUP_CLOSE and ca[i] == name then + local text + local inner = i + 1 + if inner == close then + -- group captured nothing: its value is the text it matched + text = sub(parser.input, cs[i] + 1, cs[close]) + elseif ck[inner] == CAP_STR then + text = sub(parser.input, cs[inner] + 1, cs[inner] + cz[inner]) + elseif ck[inner] == CAP_CONST then + if type(ca[inner]) ~= "string" then + return false + end + text = ca[inner] + else + return false -- group holds a non-string value + end + if parser.pos + #text <= parser.input_len and + sub(parser.input, parser.pos + 1, parser.pos + #text) == text then + parser.pos = parser.pos + #text + return true + end + return false + end + end + i = i - 1 + end + return false +end + +local floor = math.floor + +-- Run a match-time capture: materialize the inner captures, call the +-- callback with (subject, pos, ...captures), and interpret its results per +-- lpeg semantics: position/true = success, false/nil = failure, extra +-- return values become captures (stored in the parser's values array) +local function run_cmt(parser, fn, start_pos, cap_base) + local pos_after_inner = parser.pos + + local args = {parser.input, pos_after_inner + 1, n = 2} + local i = cap_base + 1 + while i <= parser.cap_n do + if parser.cap_kind[i] == CAP_GROUP_OPEN then + -- named groups only matter inside Ct; they aren't passed as arguments + i = cap_skip(parser, i) + else + i = cap_eval(parser, i, args) + end + end + parser.cap_n = cap_base -- consume the inner captures + + -- callback errors propagate (abort the parse with the original value) + local rets = pack(fn(unpack(args, 1, args.n))) + + local ok = false + if rets.n > 0 then + local first = rets[1] + if type(first) == "number" then + -- number = new position (1-based from Lua), must be in range + -- [pos_after_inner, input_len]. Floored so a fractional return can't + -- put the parser on a non-integer position. + local new_pos = floor(first) - 1 + if new_pos >= pos_after_inner and new_pos <= parser.input_len then + parser.pos = new_pos + ok = true + end + elseif first == true then + -- true = succeed without consuming (position stays at pos_after_inner) + ok = true + end + end + + if ok then + parser.success = true + if rets.n > 1 then + local values = parser.values + local vn = parser.values_n + for r = 2, rets.n do + vn = vn + 1 + values[vn] = rets[r] + cap_push(parser, CAP_VALUE, vn, 0, 0) + end + parser.values_n = vn + end + else + parser.success = false + record_furthest(parser) + parser.pos = start_pos + end +end + +-- Rewind the indenter trail to a previous length, undoing pushes and pops +local function ind_trail_rewind(parser, index) + local n = parser.trail_n + if n <= index then return end + local trail_id, trail_op, trail_val = parser.trail_id, parser.trail_op, parser.trail_val + local stacks = parser.ind_stacks + while n > index do + local s = stacks[trail_id[n]] + if trail_op[n] == 0 then + -- undo push + s.n = s.n - 1 + else + -- undo pop: restore the popped value + s.n = s.n + 1 + s[s.n] = trail_val[n] + end + n = n - 1 + end + parser.trail_n = n +end + +local function ind_push(parser, sidx, value) + local s = parser.ind_stacks[sidx] + s.n = s.n + 1 + s[s.n] = value + local tn = parser.trail_n + 1 + parser.trail_n = tn + parser.trail_id[tn] = sidx + parser.trail_op[tn] = 0 + parser.trail_val[tn] = value +end + +-- Pop the stack; returns false if the stack is empty +local function ind_pop(parser, sidx) + local s = parser.ind_stacks[sidx] + local sn = s.n + if sn == 0 then + return false + end + local value = s[sn] + s.n = sn - 1 + local tn = parser.trail_n + 1 + parser.trail_n = tn + parser.trail_id[tn] = sidx + parser.trail_op[tn] = 1 + parser.trail_val[tn] = value + return true +end + +-- Measure the indentation width of the run of space/tab characters at the +-- current position (space = 1, tab = tab_width). Also returns the first +-- position past the run. +local function ind_measure(parser, tab_width) + local input, input_len = parser.input, parser.input_len + local p = parser.pos + local width = 0 + while p < input_len do + local c = byte(input, p + 1) + if c == 32 then + width = width + 1 + elseif c == 9 then + width = width + tab_width + else + break + end + p = p + 1 + end + return width, p +end + +-- Callback (Cmt/Cfn) infrastructure: load each callback's Lua code once +do + local load_chunk = loadstring or load + do + local chunk, load_err = load_chunk(" local tree = require(\"moonscript.parse.tree\")\n return function(lhs, assign)\n return tree.format_single_assign(lhs, assign)\n end", "pgen Cfn 0") + if not chunk then + error("Failed to load Cfn callback 0: " .. tostring(load_err)) + end + local run_ok, fn = pcall(chunk) + if not run_ok then + error("Failed to run Cfn chunk 0: " .. tostring(fn)) + end + if type(fn) ~= "function" then + error("Cfn chunk 0 did not return a function") + end + cmt_fns[0] = fn + end + do + local chunk, load_err = load_chunk("return function(stm, dec)\n if dec then\n return {\"decorated\", stm, dec}\n end\n return stm\n end", "pgen Cfn 1") + if not chunk then + error("Failed to load Cfn callback 1: " .. tostring(load_err)) + end + local run_ok, fn = pcall(chunk) + if not run_ok then + error("Failed to run Cfn chunk 1: " .. tostring(fn)) + end + if type(fn) ~= "function" then + error("Cfn chunk 1 did not return a function") + end + cmt_fns[1] = fn + end + do + local chunk, load_err = load_chunk("return function(p, value)\n if type(value) == \"table\" then\n value[-1] = p\n end\n return value\n end", "pgen Cfn 2") + if not chunk then + error("Failed to load Cfn callback 2: " .. tostring(load_err)) + end + local run_ok, fn = pcall(chunk) + if not run_ok then + error("Failed to run Cfn chunk 2: " .. tostring(fn)) + end + if type(fn) ~= "function" then + error("Cfn chunk 2 did not return a function") + end + cmt_fns[2] = fn + end + do + local chunk, load_err = load_chunk(" local tree = require(\"moonscript.parse.tree\")\n return function(lhs, assign)\n return tree.format_assign(lhs, assign)\n end", "pgen Cfn 3") + if not chunk then + error("Failed to load Cfn callback 3: " .. tostring(load_err)) + end + local run_ok, fn = pcall(chunk) + if not run_ok then + error("Failed to run Cfn chunk 3: " .. tostring(fn)) + end + if type(fn) ~= "function" then + error("Cfn chunk 3 did not return a function") + end + cmt_fns[3] = fn + end + do + local chunk, load_err = load_chunk("return function(name, p)\n return {\n {\"key_literal\", name},\n {\"ref\", name, [-1] = p},\n }\n end", "pgen Cfn 4") + if not chunk then + error("Failed to load Cfn callback 4: " .. tostring(load_err)) + end + local run_ok, fn = pcall(chunk) + if not run_ok then + error("Failed to run Cfn chunk 4: " .. tostring(fn)) + end + if type(fn) ~= "function" then + error("Cfn chunk 4 did not return a function") + end + cmt_fns[4] = fn + end + do + local chunk, load_err = load_chunk(" local tree = require(\"moonscript.parse.tree\")\n return function(callee, args)\n return tree.join_chain(callee, args)\n end", "pgen Cfn 5") + if not chunk then + error("Failed to load Cfn callback 5: " .. tostring(load_err)) + end + local run_ok, fn = pcall(chunk) + if not run_ok then + error("Failed to run Cfn chunk 5: " .. tostring(fn)) + end + if type(fn) ~= "function" then + error("Cfn chunk 5 did not return a function") + end + cmt_fns[5] = fn + end + do + local chunk, load_err = load_chunk("return function(...)\n if select(\"#\", ...) == 1 then\n return ...\n end\n return {\"exp\", ...}\n end", "pgen Cfn 6") + if not chunk then + error("Failed to load Cfn callback 6: " .. tostring(load_err)) + end + local run_ok, fn = pcall(chunk) + if not run_ok then + error("Failed to run Cfn chunk 6: " .. tostring(fn)) + end + if type(fn) ~= "function" then + error("Cfn chunk 6 did not return a function") + end + cmt_fns[6] = fn + end + do + local chunk, load_err = load_chunk("return function(eq_start, eq_end, content)\n return {\"string\", \"[\" .. (\"=\"):rep(eq_end - eq_start) .. \"[\", content}\n end", "pgen Cfn 7") + if not chunk then + error("Failed to load Cfn callback 7: " .. tostring(load_err)) + end + local run_ok, fn = pcall(chunk) + if not run_ok then + error("Failed to run Cfn chunk 7: " .. tostring(fn)) + end + if type(fn) ~= "function" then + error("Cfn chunk 7 did not return a function") + end + cmt_fns[7] = fn + end + do + local chunk, load_err = load_chunk(" local subject, pos, node = ...\n local last = node[#node]\n local t = type(last) == \"table\" and last[1]\n if t == \"dot\" or t == \"index\" or t == \"slice\" then\n return pos, node\n end\n return false\n ", "pgen Cmt 8") + if not chunk then + error("Failed to load Cmt callback 8: " .. tostring(load_err)) + end + cmt_fns[8] = chunk + end +end + +-- Character set lookup tables (byte -> true) +sets[1] = { [46] = true, [92] = true } -- ".\\" +sets[2] = { [43] = true, [45] = true, [42] = true, [47] = true, [37] = true, [94] = true, [62] = true, [60] = true, [124] = true, [38] = true } -- "+-*/%^><|&" +sets[3] = { [13] = true, [10] = true } -- "\r\n" +sets[4] = { [117] = true, [85] = true } -- "uU" +sets[5] = { [108] = true, [76] = true } -- "lL" +sets[6] = { [101] = true, [69] = true } -- "eE" +sets[7] = { [32] = true, [9] = true } -- " \t" +sets[8] = { [32] = true, [9] = true, [13] = true, [10] = true } -- " \t\r\n" + +-- FIRST-byte dispatch tables +do -- dispatch tables for choice 1 + local dmask1 = { [1] = true, s = { }, full = false } + local dmask2 = { [1] = true, [2] = true, [3] = true, [4] = true, s = { }, full = true } + local dmask3 = { [1] = true, [4] = true, s = { [4] = true }, full = false } + local dmask4 = { [1] = true, [3] = true, s = { [3] = true }, full = false } + local dmask5 = { [1] = true, [2] = true, s = { }, full = false } + local bytes = {} + for b = 0, 255 do bytes[b] = dmask1 end + bytes[9] = dmask2 + bytes[32] = dmask2 + bytes[40] = dmask3 + bytes[45] = dmask2 + bytes[46] = dmask4 + bytes[64] = dmask5 + disp[1] = { bytes = bytes, eof = dmask1 } +end +do -- dispatch tables for choice 2 + local dmask1 = { [1] = true, s = { }, full = false } + local dmask2 = { [1] = true, [2] = true, s = { }, full = false } + local dmask3 = { [1] = true, [3] = true, [4] = true, s = { [3] = true, [4] = true }, full = false } + local bytes = {} + for b = 0, 255 do bytes[b] = dmask1 end + bytes[46] = dmask2 + bytes[91] = dmask3 + disp[2] = { bytes = bytes, eof = dmask1 } +end +do -- dispatch tables for choice 3 + local dmask1 = { [4] = true, s = { [4] = true }, full = false } + local dmask2 = { [1] = true, [2] = true, [3] = true, [4] = true, s = { }, full = true } + local dmask3 = { [2] = true, [4] = true, s = { [2] = true, [4] = true }, full = false } + local dmask4 = { [3] = true, [4] = true, s = { [3] = true, [4] = true }, full = false } + local dmask5 = { [1] = true, [4] = true, s = { [4] = true }, full = false } + local bytes = {} + for b = 0, 255 do bytes[b] = dmask1 end + bytes[9] = dmask2 + bytes[32] = dmask2 + bytes[42] = dmask3 + bytes[45] = dmask2 + bytes[94] = dmask4 + bytes[99] = dmask5 + disp[3] = { bytes = bytes, eof = dmask1 } +end +do -- dispatch tables for choice 4 + local dmask1 = { [4] = true, s = { [4] = true }, full = false } + local dmask2 = { [1] = true, [4] = true, s = { [4] = true }, full = false } + local dmask3 = { [3] = true, [4] = true, s = { [3] = true, [4] = true }, full = false } + local dmask4 = { [2] = true, [4] = true, s = { [2] = true, [4] = true }, full = false } + local bytes = {} + for b = 0, 255 do bytes[b] = dmask1 end + bytes[9] = dmask2 + bytes[32] = dmask2 + bytes[33] = dmask2 + bytes[34] = dmask3 + bytes[39] = dmask4 + bytes[40] = dmask2 + bytes[45] = dmask2 + disp[4] = { bytes = bytes, eof = dmask1 } +end +do -- dispatch tables for choice 5 + local dmask1 = { s = { }, full = false } + local dmask2 = { [1] = true, [2] = true, [3] = true, [4] = true, s = { }, full = true } + local dmask3 = { [3] = true, s = { [3] = true }, full = false } + local dmask4 = { [4] = true, s = { [4] = true }, full = false } + local dmask5 = { [1] = true, s = { }, full = false } + local dmask6 = { [2] = true, s = { [2] = true }, full = false } + local bytes = {} + for b = 0, 255 do bytes[b] = dmask1 end + bytes[9] = dmask2 + bytes[32] = dmask2 + bytes[34] = dmask3 + bytes[39] = dmask4 + bytes[45] = dmask2 + bytes[64] = dmask5 + bytes[65] = dmask5 + bytes[66] = dmask5 + bytes[67] = dmask5 + bytes[68] = dmask5 + bytes[69] = dmask5 + bytes[70] = dmask5 + bytes[71] = dmask5 + bytes[72] = dmask5 + bytes[73] = dmask5 + bytes[74] = dmask5 + bytes[75] = dmask5 + bytes[76] = dmask5 + bytes[77] = dmask5 + bytes[78] = dmask5 + bytes[79] = dmask5 + bytes[80] = dmask5 + bytes[81] = dmask5 + bytes[82] = dmask5 + bytes[83] = dmask5 + bytes[84] = dmask5 + bytes[85] = dmask5 + bytes[86] = dmask5 + bytes[87] = dmask5 + bytes[88] = dmask5 + bytes[89] = dmask5 + bytes[90] = dmask5 + bytes[91] = dmask6 + bytes[95] = dmask5 + bytes[97] = dmask5 + bytes[98] = dmask5 + bytes[99] = dmask5 + bytes[100] = dmask5 + bytes[101] = dmask5 + bytes[102] = dmask5 + bytes[103] = dmask5 + bytes[104] = dmask5 + bytes[105] = dmask5 + bytes[106] = dmask5 + bytes[107] = dmask5 + bytes[108] = dmask5 + bytes[109] = dmask5 + bytes[110] = dmask5 + bytes[111] = dmask5 + bytes[112] = dmask5 + bytes[113] = dmask5 + bytes[114] = dmask5 + bytes[115] = dmask5 + bytes[116] = dmask5 + bytes[117] = dmask5 + bytes[118] = dmask5 + bytes[119] = dmask5 + bytes[120] = dmask5 + bytes[121] = dmask5 + bytes[122] = dmask5 + disp[5] = { bytes = bytes, eof = dmask1 } +end +do -- dispatch tables for choice 6 + local dmask1 = { [9] = true, s = { [9] = true }, full = false } + local dmask2 = { [1] = true, [2] = true, [3] = true, [4] = true, [5] = true, [6] = true, [7] = true, [8] = true, [9] = true, [10] = true, [11] = true, [12] = true, [13] = true, [14] = true, [15] = true, [16] = true, [17] = true, [18] = true, s = { }, full = true } + local dmask3 = { [9] = true, [11] = true, s = { [9] = true, [11] = true }, full = false } + local dmask4 = { [9] = true, [17] = true, s = { [9] = true, [17] = true }, full = false } + local dmask5 = { [9] = true, [18] = true, s = { [9] = true, [18] = true }, full = false } + local dmask6 = { [9] = true, [16] = true, s = { [9] = true, [16] = true }, full = false } + local dmask7 = { [5] = true, [9] = true, s = { [5] = true, [9] = true }, full = false } + local dmask8 = { [6] = true, [7] = true, [9] = true, s = { [6] = true, [7] = true, [9] = true }, full = false } + local dmask9 = { [1] = true, [9] = true, s = { [9] = true }, full = false } + local dmask10 = { [9] = true, [13] = true, s = { [9] = true, [13] = true }, full = false } + local dmask11 = { [3] = true, [9] = true, s = { [3] = true, [9] = true }, full = false } + local dmask12 = { [2] = true, [9] = true, s = { [2] = true, [9] = true }, full = false } + local dmask13 = { [4] = true, [8] = true, [9] = true, s = { [4] = true, [8] = true, [9] = true }, full = false } + local dmask14 = { [9] = true, [14] = true, [15] = true, s = { [9] = true, [14] = true, [15] = true }, full = false } + local dmask15 = { [9] = true, [12] = true, s = { [9] = true, [12] = true }, full = false } + local bytes = {} + for b = 0, 255 do bytes[b] = dmask1 end + bytes[9] = dmask2 + bytes[32] = dmask2 + bytes[35] = dmask3 + bytes[40] = dmask4 + bytes[45] = dmask2 + bytes[46] = dmask5 + bytes[48] = dmask5 + bytes[49] = dmask5 + bytes[50] = dmask5 + bytes[51] = dmask5 + bytes[52] = dmask5 + bytes[53] = dmask5 + bytes[54] = dmask5 + bytes[55] = dmask5 + bytes[56] = dmask5 + bytes[57] = dmask5 + bytes[61] = dmask4 + bytes[91] = dmask6 + bytes[99] = dmask7 + bytes[102] = dmask8 + bytes[105] = dmask9 + bytes[110] = dmask10 + bytes[115] = dmask11 + bytes[117] = dmask12 + bytes[119] = dmask13 + bytes[123] = dmask14 + bytes[126] = dmask15 + disp[6] = { bytes = bytes, eof = dmask1 } +end +do -- dispatch tables for choice 7 + local dmask1 = { [11] = true, s = { [11] = true }, full = false } + local dmask2 = { [1] = true, [2] = true, [3] = true, [4] = true, [5] = true, [6] = true, [7] = true, [8] = true, [9] = true, [10] = true, [11] = true, s = { }, full = true } + local dmask3 = { [10] = true, [11] = true, s = { [10] = true, [11] = true }, full = false } + local dmask4 = { [9] = true, [11] = true, s = { [9] = true, [11] = true }, full = false } + local dmask5 = { [4] = true, [5] = true, [11] = true, s = { [4] = true, [5] = true, [11] = true }, full = false } + local dmask6 = { [1] = true, [11] = true, s = { [11] = true }, full = false } + local dmask7 = { [8] = true, [11] = true, s = { [8] = true, [11] = true }, full = false } + local dmask8 = { [7] = true, [11] = true, s = { [7] = true, [11] = true }, full = false } + local dmask9 = { [6] = true, [11] = true, s = { [6] = true, [11] = true }, full = false } + local dmask10 = { [2] = true, [3] = true, [11] = true, s = { [2] = true, [3] = true, [11] = true }, full = false } + local bytes = {} + for b = 0, 255 do bytes[b] = dmask1 end + bytes[9] = dmask2 + bytes[32] = dmask2 + bytes[45] = dmask2 + bytes[98] = dmask3 + bytes[99] = dmask3 + bytes[101] = dmask4 + bytes[102] = dmask5 + bytes[105] = dmask6 + bytes[108] = dmask7 + bytes[114] = dmask8 + bytes[115] = dmask9 + bytes[119] = dmask10 + disp[7] = { bytes = bytes, eof = dmask1 } +end +do -- dispatch tables for choice 8 + local dmask1 = { [1] = true, [3] = true, s = { [3] = true }, full = false } + local dmask2 = { [1] = true, [2] = true, [3] = true, [4] = true, s = { }, full = true } + local dmask3 = { [1] = true, [2] = true, [3] = true, s = { }, full = false } + local bytes = {} + for b = 0, 255 do bytes[b] = dmask1 end + bytes[9] = dmask2 + bytes[32] = dmask2 + bytes[34] = dmask2 + bytes[39] = dmask2 + bytes[45] = dmask2 + bytes[58] = dmask3 + bytes[64] = dmask3 + bytes[65] = dmask3 + bytes[66] = dmask3 + bytes[67] = dmask3 + bytes[68] = dmask3 + bytes[69] = dmask3 + bytes[70] = dmask3 + bytes[71] = dmask3 + bytes[72] = dmask3 + bytes[73] = dmask3 + bytes[74] = dmask3 + bytes[75] = dmask3 + bytes[76] = dmask3 + bytes[77] = dmask3 + bytes[78] = dmask3 + bytes[79] = dmask3 + bytes[80] = dmask3 + bytes[81] = dmask3 + bytes[82] = dmask3 + bytes[83] = dmask3 + bytes[84] = dmask3 + bytes[85] = dmask3 + bytes[86] = dmask3 + bytes[87] = dmask3 + bytes[88] = dmask3 + bytes[89] = dmask3 + bytes[90] = dmask3 + bytes[91] = dmask2 + bytes[95] = dmask3 + bytes[97] = dmask3 + bytes[98] = dmask3 + bytes[99] = dmask3 + bytes[100] = dmask3 + bytes[101] = dmask3 + bytes[102] = dmask3 + bytes[103] = dmask3 + bytes[104] = dmask3 + bytes[105] = dmask3 + bytes[106] = dmask3 + bytes[107] = dmask3 + bytes[108] = dmask3 + bytes[109] = dmask3 + bytes[110] = dmask3 + bytes[111] = dmask3 + bytes[112] = dmask3 + bytes[113] = dmask3 + bytes[114] = dmask3 + bytes[115] = dmask3 + bytes[116] = dmask3 + bytes[117] = dmask3 + bytes[118] = dmask3 + bytes[119] = dmask3 + bytes[120] = dmask3 + bytes[121] = dmask3 + bytes[122] = dmask3 + disp[8] = { bytes = bytes, eof = dmask1 } +end +do -- dispatch tables for choice 9 + local dmask1 = { s = { }, full = false } + local dmask2 = { [1] = true, [2] = true, [3] = true, [4] = true, [5] = true, [6] = true, [7] = true, [8] = true, [9] = true, [10] = true, [11] = true, s = { }, full = true } + local dmask3 = { [6] = true, s = { [6] = true }, full = false } + local dmask4 = { [8] = true, s = { [8] = true }, full = false } + local dmask5 = { [11] = true, s = { [11] = true }, full = false } + local dmask6 = { [3] = true, [9] = true, s = { [3] = true, [9] = true }, full = false } + local dmask7 = { [7] = true, s = { [7] = true }, full = false } + local dmask8 = { [4] = true, [10] = true, s = { [4] = true, [10] = true }, full = false } + local dmask9 = { [2] = true, s = { [2] = true }, full = false } + local dmask10 = { [1] = true, s = { }, full = false } + local dmask11 = { [5] = true, s = { [5] = true }, full = false } + local bytes = {} + for b = 0, 255 do bytes[b] = dmask1 end + bytes[9] = dmask2 + bytes[32] = dmask2 + bytes[33] = dmask3 + bytes[45] = dmask2 + bytes[46] = dmask4 + bytes[47] = dmask5 + bytes[60] = dmask6 + bytes[61] = dmask7 + bytes[62] = dmask8 + bytes[97] = dmask9 + bytes[111] = dmask10 + bytes[126] = dmask11 + disp[9] = { bytes = bytes, eof = dmask1 } +end + +-- Rule functions +rules["Root"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- sequence with 4 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["White"](parser) +if parser.success then +rules["File"](parser) +end +if parser.success then +rules["White"](parser) +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + -- match any 1 characters +if parser.pos + 1 <= parser.input_len then + parser.pos = parser.pos + 1 +else + parser.success = false + record_furthest(parser) + +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["Advance"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- indenter advance (stack 0): push width if deeper than top, consume nothing + local ind_width = ind_measure(parser, 4) + local ind_s = parser.ind_stacks[1] + if ind_s.n > 0 and ind_width > ind_s[ind_s.n] then + ind_push(parser, 1, ind_width) + else + parser.success = false + record_furthest(parser) + + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["ArgBlock"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["ArgLine"](parser) +if parser.success then +do -- zero or more repetitions + while true do + do -- sequence with 4 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +-- match single character "," +if byte(parser.input, parser.pos + 1) == 44 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end +if parser.success then +rules["SpaceBreak"](parser) +end +if parser.success then +rules["ArgLine"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if not parser.success then + break + end + end + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end +end +end +if parser.success then +rules["PopIndent"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["ArgLine"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["CheckIndent"](parser) +if parser.success then +rules["ExpList"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["Assign"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 4 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "assign", 0, 0) +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match single character "=" +if byte(parser.input, parser.pos + 1) == 61 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end +if parser.success then +do -- choice with 2 alternatives + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- choice with 3 alternatives + rules["With"](parser) +if not parser.success and not parser.throw_label then + parser.success = true + rules["If"](parser) +end +if not parser.success and not parser.throw_label then + parser.success = true + rules["Switch"](parser) +end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +if not parser.success and not parser.throw_label then + parser.success = true + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- choice with 2 alternatives + rules["TableBlock"](parser) +if not parser.success and not parser.throw_label then + parser.success = true + rules["ExpListLow"](parser) +end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["Assignable"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- choice with 3 alternatives + do -- match-time capture (Cmt id=8) + local cmt_cap_base = parser.cap_n + local cmt_start_pos = parser.pos + local cmt_trail = parser.trail_n + rules["Chain"](parser) + if parser.success then + run_cmt(parser, cmt_fns[8], cmt_start_pos, cmt_cap_base) + if not parser.success then + ind_trail_rewind(parser, cmt_trail) + end + end +end +if not parser.success and not parser.throw_label then + parser.success = true + rules["Name"](parser) +end +if not parser.success and not parser.throw_label then + parser.success = true + rules["SelfName"](parser) +end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["AssignableNameList"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["NameOrDestructure"](parser) +if parser.success then +do -- zero or more repetitions + while true do + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +-- match single character "," +if byte(parser.input, parser.pos + 1) == 44 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end +if parser.success then +rules["NameOrDestructure"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if not parser.success then + break + end + end + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["BinaryOperator"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- choice with 2 alternatives + rules["WordOperators"](parser) +if not parser.success and not parser.throw_label then + parser.success = true + rules["CharOperators"](parser) +end +end +if parser.success then +do -- zero or more repetitions + while true do + rules["SpaceBreak"](parser) + if not parser.success then + break + end + end + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["Block"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Line"](parser) +if parser.success then +do -- zero or more repetitions + while true do + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- at least 1 repetitions + local pp_pos = parser.pos + local rep_count = 0 + while true do + rules["Break"](parser) + if not parser.success then + break + end + rep_count = rep_count + 1 + end + if parser.throw_label then + -- Keep failure state, propagate labeled failure + elseif rep_count >= 1 then + parser.success = true + else + parser.pos = pp_pos + + end +end +if parser.success then +rules["Line"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if not parser.success then + break + end + end + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["Body"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- choice with 2 alternatives + do -- sequence with 4 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +rules["Break"](parser) +end +if parser.success then +do -- zero or more repetitions + while true do + rules["EmptyLine"](parser) + if not parser.success then + break + end + end + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end +end +end +if parser.success then +rules["InBlock"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +if not parser.success and not parser.throw_label then + parser.success = true + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + rules["Statement"](parser) + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["Break"] = function(parser) + local start = parser.pos + -- Position-pure rule: a single-slot memo short-circuits the repeated + -- calls that backtracking alternatives make at the same position + if parser.memo_pos[1] == start + 1 then + local memo_end = parser.memo_end[1] + if memo_end == -1 then + parser.success = false + return false + end + parser.pos = memo_end + parser.success = true + return true + end +local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- sequence with 2 patterns + local pp_pos = parser.pos + do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + -- match single character "\r" +if byte(parser.input, parser.pos + 1) == 13 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +if parser.success then +-- match single character "\n" +if byte(parser.input, parser.pos + 1) == 10 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end + if not parser.success then + parser.pos = pp_pos + end +end + parser.memo_pos[1] = start + 1 + parser.memo_end[1] = parser.success and parser.pos or -1 + + parser.depth = depth - 1 + return parser.success +end + + +rules["BreakLoop"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- choice with 2 alternatives + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 4 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +-- match literal "break" +if sub(parser.input, parser.pos + 1, parser.pos + 5) == "break" then + parser.pos = parser.pos + 5 +else + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character range "az,AZ,09,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 48 and rb <= 57) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end +if parser.success then +do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "break", 0, 0) +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +if not parser.success and not parser.throw_label then + parser.success = true + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 4 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +-- match literal "continue" +if sub(parser.input, parser.pos + 1, parser.pos + 8) == "continue" then + parser.pos = parser.pos + 8 +else + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character range "az,AZ,09,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 48 and rb <= 57) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end +if parser.success then +do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "continue", 0, 0) +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["Callable"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- FIRST-byte dispatched ordered choice + local dd = disp[1] + local db = byte(parser.input, parser.pos + 1) + local dm = db and dd.bytes[db] or dd.eof + parser.success = false + if not parser.success and not parser.throw_label and dm[1] then + parser.success = true + do -- transform capture (Cfn id=2) + local fn_cap_start = parser.cap_n + cap_push(parser, CAP_FN_OPEN, cmt_fns[2], parser.pos, 0) + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + cap_push(parser, CAP_POS, nil, parser.pos, 0) -- position capture +if parser.success then +do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "ref", 0, 0) +end +if parser.success then +rules["Name"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_FN_CLOSE, nil, parser.pos, 0) + else + parser.cap_n = fn_cap_start + end +end +end +if not parser.success and not parser.throw_label and dm[2] then + if dm.s[2] then record_furthest(parser) end + parser.success = true + rules["SelfName"](parser) +end +if not parser.success and not parser.throw_label and dm[3] then + if dm.s[3] then record_furthest(parser) end + parser.success = true + rules["VarArg"](parser) +end +if not parser.success and not parser.throw_label and dm[4] then + if dm.s[4] then record_furthest(parser) end + parser.success = true + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "parens", 0, 0) +end +if parser.success then +rules["Parens"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end + if not parser.success and not parser.throw_label then + record_furthest(parser) + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["Chain"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- choice with 2 alternatives + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "chain", 0, 0) +end +if parser.success then +do -- choice with 3 alternatives + rules["Callable"](parser) +if not parser.success and not parser.throw_label then + parser.success = true + rules["String"](parser) +end +if not parser.success and not parser.throw_label then + parser.success = true + do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character set ".\\" + local sb = byte(parser.input, parser.pos + 1) + if sb and sets[1][sb] then + parser.pos = parser.pos + 1 + else + parser.success = false + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end +end +end +if parser.success then +rules["ChainItems"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +if not parser.success and not parser.throw_label then + parser.success = true + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "chain", 0, 0) +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +do -- choice with 2 alternatives + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["DotChainItem"](parser) +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + rules["ChainItems"](parser) + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +if not parser.success and not parser.throw_label then + parser.success = true + rules["ColonChain"](parser) +end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["ChainItem"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- FIRST-byte dispatched ordered choice + local dd = disp[2] + local db = byte(parser.input, parser.pos + 1) + local dm = db and dd.bytes[db] or dd.eof + parser.success = false + if not parser.success and not parser.throw_label and dm[1] then + parser.success = true + rules["Invoke"](parser) +end +if not parser.success and not parser.throw_label and dm[2] then + if dm.s[2] then record_furthest(parser) end + parser.success = true + rules["DotChainItem"](parser) +end +if not parser.success and not parser.throw_label and dm[3] then + if dm.s[3] then record_furthest(parser) end + parser.success = true + rules["Slice"](parser) +end +if not parser.success and not parser.throw_label and dm[4] then + if dm.s[4] then record_furthest(parser) end + parser.success = true + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "index", 0, 0) +end +if parser.success then +-- match single character "[" +if byte(parser.input, parser.pos + 1) == 91 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end +if parser.success then +rules["Exp"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match single character "]" +if byte(parser.input, parser.pos + 1) == 93 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +end + if not parser.success and not parser.throw_label then + record_furthest(parser) + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["ChainItems"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- choice with 2 alternatives + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- at least 1 repetitions + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + local rep_count = 0 + while true do + rules["ChainItem"](parser) + if not parser.success then + break + end + rep_count = rep_count + 1 + end + if parser.throw_label then + -- Keep failure state, propagate labeled failure + elseif rep_count >= 1 then + parser.success = true + else + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + + end +end +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + rules["ColonChain"](parser) + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +if not parser.success and not parser.throw_label then + parser.success = true + rules["ColonChain"](parser) +end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["ChainValue"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- transform capture (Cfn id=5) + local fn_cap_start = parser.cap_n + cap_push(parser, CAP_FN_OPEN, cmt_fns[5], parser.pos, 0) + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- choice with 2 alternatives + rules["Chain"](parser) +if not parser.success and not parser.throw_label then + parser.success = true + rules["Callable"](parser) +end +end +if parser.success then +do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + rules["InvokeArgs"](parser) + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_FN_CLOSE, nil, parser.pos, 0) + else + parser.cap_n = fn_cap_start + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["CharOperators"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +do -- capture + local cap_start_pos = parser.pos + do -- match character set "+-*/%^><|&" + local sb = byte(parser.input, parser.pos + 1) + if sb and sets[2][sb] then + parser.pos = parser.pos + 1 + else + parser.success = false + end +end + if parser.success then + cap_push(parser, CAP_STR, nil, cap_start_pos, parser.pos - cap_start_pos) + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["CheckIndent"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- indenter check (stack 0): consume whitespace, width must equal top + local ind_width, ind_end = ind_measure(parser, 4) + local ind_s = parser.ind_stacks[1] + if ind_s.n > 0 and ind_s[ind_s.n] == ind_width then + parser.pos = ind_end + else + parser.success = false + record_furthest(parser) + + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["ClassBlock"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- sequence with 4 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- at least 1 repetitions + local pp_pos = parser.pos + local rep_count = 0 + while true do + rules["SpaceBreak"](parser) + if not parser.success then + break + end + rep_count = rep_count + 1 + end + if parser.throw_label then + -- Keep failure state, propagate labeled failure + elseif rep_count >= 1 then + parser.success = true + else + parser.pos = pp_pos + + end +end +if parser.success then +rules["Advance"](parser) +end +if parser.success then +do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["ClassLine"](parser) +if parser.success then +do -- zero or more repetitions + while true do + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- at least 1 repetitions + local pp_pos = parser.pos + local rep_count = 0 + while true do + rules["SpaceBreak"](parser) + if not parser.success then + break + end + rep_count = rep_count + 1 + end + if parser.throw_label then + -- Keep failure state, propagate labeled failure + elseif rep_count >= 1 then + parser.success = true + else + parser.pos = pp_pos + + end +end +if parser.success then +rules["ClassLine"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if not parser.success then + break + end + end + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end +if parser.success then +rules["PopIndent"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["ClassDecl"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 8 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "class", 0, 0) +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match literal "class" +if sub(parser.input, parser.pos + 1, parser.pos + 5) == "class" then + parser.pos = parser.pos + 5 +else + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character range "az,AZ,09,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 48 and rb <= 57) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + -- match single character ":" +if byte(parser.input, parser.pos + 1) == 58 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end +if parser.success then +do -- choice with 2 alternatives + rules["Assignable"](parser) +if not parser.success and not parser.throw_label then + parser.success = true + do -- constant capture (1 values) + cap_push(parser, CAP_NIL, nil, 0, 0) +end +end +end +end +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + do -- choice with 2 alternatives + do -- sequence with 6 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +-- match literal "extends" +if sub(parser.input, parser.pos + 1, parser.pos + 7) == "extends" then + parser.pos = parser.pos + 7 +else + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character range "az,AZ,09,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 48 and rb <= 57) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end +if parser.success then +rules["PreventIndent"](parser) +end +if parser.success then +rules["Exp"](parser) +end +if parser.success then +rules["PopIndent"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +if not parser.success and not parser.throw_label then + parser.success = true + do -- capture + local cap_start_pos = parser.pos + -- match literal "" +if sub(parser.input, parser.pos + 1, parser.pos + 0) == "" then + parser.pos = parser.pos + 0 +else + parser.success = false + record_furthest(parser) + +end + if parser.success then + cap_push(parser, CAP_STR, nil, cap_start_pos, parser.pos - cap_start_pos) + end +end +end +end + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end +if parser.success then +do -- choice with 2 alternatives + rules["ClassBlock"](parser) +if not parser.success and not parser.throw_label then + parser.success = true + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + -- match literal "" +if sub(parser.input, parser.pos + 1, parser.pos + 0) == "" then + parser.pos = parser.pos + 0 +else + parser.success = false + record_furthest(parser) + +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["ClassLine"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["CheckIndent"](parser) +if parser.success then +do -- choice with 3 alternatives + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "props", 0, 0) +end +if parser.success then +rules["KeyValueList"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +if not parser.success and not parser.throw_label then + parser.success = true + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "stm", 0, 0) +end +if parser.success then +rules["Statement"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end +if not parser.success and not parser.throw_label then + parser.success = true + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "stm", 0, 0) +end +if parser.success then +rules["Exp"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end +end +end +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + do -- sequence with 2 patterns + local pp_pos = parser.pos + rules["Space"](parser) +if parser.success then +-- match single character "," +if byte(parser.input, parser.pos + 1) == 44 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end + if not parser.success then + parser.pos = pp_pos + end +end + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["ColonChain"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["ColonChainItem"](parser) +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Invoke"](parser) +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + rules["ChainItems"](parser) + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["ColonChainItem"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "colon", 0, 0) +end +if parser.success then +-- match single character "\\" +if byte(parser.input, parser.pos + 1) == 92 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end +if parser.success then +rules["NameRaw"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["Comment"] = function(parser) + local start = parser.pos + -- Position-pure rule: a single-slot memo short-circuits the repeated + -- calls that backtracking alternatives make at the same position + if parser.memo_pos[2] == start + 1 then + local memo_end = parser.memo_end[2] + if memo_end == -1 then + parser.success = false + return false + end + parser.pos = memo_end + parser.success = true + return true + end +local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- sequence with 3 patterns + local pp_pos = parser.pos + -- match literal "--" +if sub(parser.input, parser.pos + 1, parser.pos + 2) == "--" then + parser.pos = parser.pos + 2 +else + parser.success = false + record_furthest(parser) + +end +if parser.success then +do -- zero or more repetitions + while true do + do -- sequence with 2 patterns + local pp_pos = parser.pos + do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character set "\r\n" + local sb = byte(parser.input, parser.pos + 1) + if sb and sets[3][sb] then + parser.pos = parser.pos + 1 + else + parser.success = false + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +if parser.success then +-- match any 1 characters +if parser.pos + 1 <= parser.input_len then + parser.pos = parser.pos + 1 +else + parser.success = false + record_furthest(parser) + +end +end + if not parser.success then + parser.pos = pp_pos + end +end + if not parser.success then + break + end + end + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end +end +end +if parser.success then +do -- lookahead (match without consuming input) + local pp_pos = parser.pos + rules["Stop"](parser) + if parser.success then + parser.pos = pp_pos + end +end +end + if not parser.success then + parser.pos = pp_pos + end +end + parser.memo_pos[2] = start + 1 + parser.memo_end[2] = parser.success and parser.pos or -1 + + parser.depth = depth - 1 + return parser.success +end + + +rules["CompClause"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- choice with 3 alternatives + rules["CompFor"](parser) +if not parser.success and not parser.throw_label then + parser.success = true + rules["CompForEach"](parser) +end +if not parser.success and not parser.throw_label then + parser.success = true + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 5 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "when", 0, 0) +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match literal "when" +if sub(parser.input, parser.pos + 1, parser.pos + 4) == "when" then + parser.pos = parser.pos + 4 +else + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character range "az,AZ,09,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 48 and rb <= 57) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end +if parser.success then +rules["Exp"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["CompFor"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 6 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "for", 0, 0) +end +if parser.success then +-- match literal "for" +if sub(parser.input, parser.pos + 1, parser.pos + 3) == "for" then + parser.pos = parser.pos + 3 +else + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +rules["Name"](parser) +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match single character "=" +if byte(parser.input, parser.pos + 1) == 61 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end +if parser.success then +do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 5 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Exp"](parser) +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match single character "," +if byte(parser.input, parser.pos + 1) == 44 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end +if parser.success then +rules["Exp"](parser) +end +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +-- match single character "," +if byte(parser.input, parser.pos + 1) == 44 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end +if parser.success then +rules["Exp"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character range "az,AZ,09,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 48 and rb <= 57) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["CompForEach"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 9 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "foreach", 0, 0) +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match literal "for" +if sub(parser.input, parser.pos + 1, parser.pos + 3) == "for" then + parser.pos = parser.pos + 3 +else + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character range "az,AZ,09,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 48 and rb <= 57) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end +if parser.success then +do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + rules["AssignableNameList"](parser) + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match literal "in" +if sub(parser.input, parser.pos + 1, parser.pos + 2) == "in" then + parser.pos = parser.pos + 2 +else + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character range "az,AZ,09,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 48 and rb <= 57) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end +if parser.success then +do -- choice with 2 alternatives + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +-- match single character "*" +if byte(parser.input, parser.pos + 1) == 42 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end +if parser.success then +do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "unpack", 0, 0) +end +if parser.success then +rules["Exp"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +if not parser.success and not parser.throw_label then + parser.success = true + rules["Exp"](parser) +end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["CompInner"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- choice with 2 alternatives + rules["CompForEach"](parser) +if not parser.success and not parser.throw_label then + parser.success = true + rules["CompFor"](parser) +end +end +if parser.success then +do -- zero or more repetitions + while true do + rules["CompClause"](parser) + if not parser.success then + break + end + end + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["Comprehension"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 7 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "comprehension", 0, 0) +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match single character "[" +if byte(parser.input, parser.pos + 1) == 91 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end +if parser.success then +rules["Exp"](parser) +end +if parser.success then +rules["CompInner"](parser) +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match single character "]" +if byte(parser.input, parser.pos + 1) == 93 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["Do"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 5 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "do", 0, 0) +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match literal "do" +if sub(parser.input, parser.pos + 1, parser.pos + 2) == "do" then + parser.pos = parser.pos + 2 +else + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character range "az,AZ,09,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 48 and rb <= 57) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end +if parser.success then +rules["Body"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["DotChainItem"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "dot", 0, 0) +end +if parser.success then +-- match single character "." +if byte(parser.input, parser.pos + 1) == 46 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end +if parser.success then +rules["NameRaw"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["DoubleString"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 4 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "string", 0, 0) +end +if parser.success then +do -- capture + local cap_start_pos = parser.pos + -- match single character "\"" +if byte(parser.input, parser.pos + 1) == 34 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end + if parser.success then + cap_push(parser, CAP_STR, nil, cap_start_pos, parser.pos - cap_start_pos) + end +end +end +if parser.success then +do -- zero or more repetitions + while true do + do -- choice with 2 alternatives + do -- capture + local cap_start_pos = parser.pos + do -- at least 1 repetitions + local pp_pos = parser.pos + local rep_count = 0 + while true do + do -- sequence with 2 patterns + local pp_pos = parser.pos + do -- negate (only match if pattern fails) + local pp_pos = parser.pos + -- match literal "#{" +if sub(parser.input, parser.pos + 1, parser.pos + 2) == "#{" then + parser.pos = parser.pos + 2 +else + parser.success = false + record_furthest(parser) + +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +if parser.success then +rules["DoubleStringInner"](parser) +end + if not parser.success then + parser.pos = pp_pos + end +end + if not parser.success then + break + end + rep_count = rep_count + 1 + end + if parser.throw_label then + -- Keep failure state, propagate labeled failure + elseif rep_count >= 1 then + parser.success = true + else + parser.pos = pp_pos + + end +end + if parser.success then + cap_push(parser, CAP_STR, nil, cap_start_pos, parser.pos - cap_start_pos) + end +end +if not parser.success and not parser.throw_label then + parser.success = true + rules["DoubleStringInterp"](parser) +end +end + if not parser.success then + break + end + end + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end +end +end +if parser.success then +-- match single character "\"" +if byte(parser.input, parser.pos + 1) == 34 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["DoubleStringInner"] = function(parser) + local start = parser.pos + -- Position-pure rule: a single-slot memo short-circuits the repeated + -- calls that backtracking alternatives make at the same position + if parser.memo_pos[3] == start + 1 then + local memo_end = parser.memo_end[3] + if memo_end == -1 then + parser.success = false + return false + end + parser.pos = memo_end + parser.success = true + return true + end +local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- choice with 3 alternatives + -- match literal "\\\"" +if sub(parser.input, parser.pos + 1, parser.pos + 2) == "\\\"" then + parser.pos = parser.pos + 2 +else + parser.success = false + record_furthest(parser) + +end +if not parser.success and not parser.throw_label then + parser.success = true + -- match literal "\\\\" +if sub(parser.input, parser.pos + 1, parser.pos + 2) == "\\\\" then + parser.pos = parser.pos + 2 +else + parser.success = false + record_furthest(parser) + +end +end +if not parser.success and not parser.throw_label then + parser.success = true + do -- sequence with 2 patterns + local pp_pos = parser.pos + do -- negate (only match if pattern fails) + local pp_pos = parser.pos + -- match single character "\"" +if byte(parser.input, parser.pos + 1) == 34 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +if parser.success then +-- match any 1 characters +if parser.pos + 1 <= parser.input_len then + parser.pos = parser.pos + 1 +else + parser.success = false + record_furthest(parser) + +end +end + if not parser.success then + parser.pos = pp_pos + end +end +end +end + parser.memo_pos[3] = start + 1 + parser.memo_end[3] = parser.success and parser.pos or -1 + + parser.depth = depth - 1 + return parser.success +end + + +rules["DoubleStringInterp"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 5 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "interpolate", 0, 0) +end +if parser.success then +-- match literal "#{" +if sub(parser.input, parser.pos + 1, parser.pos + 2) == "#{" then + parser.pos = parser.pos + 2 +else + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +rules["Exp"](parser) +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match single character "}" +if byte(parser.input, parser.pos + 1) == 125 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["EmptyLine"] = function(parser) + local start = parser.pos + -- Position-pure rule: a single-slot memo short-circuits the repeated + -- calls that backtracking alternatives make at the same position + if parser.memo_pos[4] == start + 1 then + local memo_end = parser.memo_end[4] + if memo_end == -1 then + parser.success = false + return false + end + parser.pos = memo_end + parser.success = true + return true + end +local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + rules["SpaceBreak"](parser) + parser.memo_pos[4] = start + 1 + parser.memo_end[4] = parser.success and parser.pos or -1 + + parser.depth = depth - 1 + return parser.success +end + + +rules["Exp"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- transform capture (Cfn id=6) + local fn_cap_start = parser.cap_n + cap_push(parser, CAP_FN_OPEN, cmt_fns[6], parser.pos, 0) + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Value"](parser) +if parser.success then +do -- zero or more repetitions + while true do + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["BinaryOperator"](parser) +if parser.success then +rules["Value"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if not parser.success then + break + end + end + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_FN_CLOSE, nil, parser.pos, 0) + else + parser.cap_n = fn_cap_start + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["ExpList"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Exp"](parser) +if parser.success then +do -- zero or more repetitions + while true do + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +-- match single character "," +if byte(parser.input, parser.pos + 1) == 44 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end +if parser.success then +rules["Exp"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if not parser.success then + break + end + end + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["ExpListLow"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Exp"](parser) +if parser.success then +do -- zero or more repetitions + while true do + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- choice with 2 alternatives + do -- sequence with 2 patterns + local pp_pos = parser.pos + rules["Space"](parser) +if parser.success then +-- match single character "," +if byte(parser.input, parser.pos + 1) == 44 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end + if not parser.success then + parser.pos = pp_pos + end +end +if not parser.success and not parser.throw_label then + parser.success = true + do -- sequence with 2 patterns + local pp_pos = parser.pos + rules["Space"](parser) +if parser.success then +-- match single character ";" +if byte(parser.input, parser.pos + 1) == 59 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end + if not parser.success then + parser.pos = pp_pos + end +end +end +end +if parser.success then +rules["Exp"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if not parser.success then + break + end + end + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["Export"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 5 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "export", 0, 0) +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match literal "export" +if sub(parser.input, parser.pos + 1, parser.pos + 6) == "export" then + parser.pos = parser.pos + 6 +else + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character range "az,AZ,09,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 48 and rb <= 57) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end +if parser.success then +do -- FIRST-byte dispatched ordered choice + local dd = disp[3] + local db = byte(parser.input, parser.pos + 1) + local dm = db and dd.bytes[db] or dd.eof + parser.success = false + if not parser.success and not parser.throw_label and dm[1] then + parser.success = true + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "class", 0, 0) +end +if parser.success then +rules["ClassDecl"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +end +if not parser.success and not parser.throw_label and dm[2] then + if dm.s[2] then record_furthest(parser) end + parser.success = true + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +do -- capture + local cap_start_pos = parser.pos + -- match single character "*" +if byte(parser.input, parser.pos + 1) == 42 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end + if parser.success then + cap_push(parser, CAP_STR, nil, cap_start_pos, parser.pos - cap_start_pos) + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +end +if not parser.success and not parser.throw_label and dm[3] then + if dm.s[3] then record_furthest(parser) end + parser.success = true + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +do -- capture + local cap_start_pos = parser.pos + -- match single character "^" +if byte(parser.input, parser.pos + 1) == 94 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end + if parser.success then + cap_push(parser, CAP_STR, nil, cap_start_pos, parser.pos - cap_start_pos) + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +end +if not parser.success and not parser.throw_label and dm[4] then + if dm.s[4] then record_furthest(parser) end + parser.success = true + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + rules["NameList"](parser) + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +-- match single character "=" +if byte(parser.input, parser.pos + 1) == 61 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end +if parser.success then +do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + rules["ExpListLow"](parser) + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +end + if not parser.success and not parser.throw_label then + record_furthest(parser) + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["File"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + rules["Shebang"](parser) + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +if parser.success then +do -- choice with 2 alternatives + rules["Block"](parser) +if not parser.success and not parser.throw_label then + parser.success = true + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + -- match literal "" +if sub(parser.input, parser.pos + 1, parser.pos + 0) == "" then + parser.pos = parser.pos + 0 +else + parser.success = false + record_furthest(parser) + +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["FnArgDef"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- choice with 3 alternatives + rules["Name"](parser) +if not parser.success and not parser.throw_label then + parser.success = true + rules["SelfName"](parser) +end +if not parser.success and not parser.throw_label then + parser.success = true + rules["TableLit"](parser) +end +end +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +-- match single character "=" +if byte(parser.input, parser.pos + 1) == 61 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end +if parser.success then +rules["Exp"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["FnArgDefList"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- choice with 2 alternatives + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["FnArgDef"](parser) +if parser.success then +do -- zero or more repetitions + while true do + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- choice with 2 alternatives + do -- sequence with 2 patterns + local pp_pos = parser.pos + rules["Space"](parser) +if parser.success then +-- match single character "," +if byte(parser.input, parser.pos + 1) == 44 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end + if not parser.success then + parser.pos = pp_pos + end +end +if not parser.success and not parser.throw_label then + parser.success = true + rules["Break"](parser) +end +end +if parser.success then +rules["White"](parser) +end +if parser.success then +rules["FnArgDef"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if not parser.success then + break + end + end + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end +end +end +if parser.success then +do -- zero or more repetitions + while true do + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- choice with 2 alternatives + do -- sequence with 2 patterns + local pp_pos = parser.pos + rules["Space"](parser) +if parser.success then +-- match single character "," +if byte(parser.input, parser.pos + 1) == 44 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end + if not parser.success then + parser.pos = pp_pos + end +end +if not parser.success and not parser.throw_label then + parser.success = true + rules["Break"](parser) +end +end +if parser.success then +rules["White"](parser) +end +if parser.success then +do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + rules["VarArg"](parser) + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if not parser.success then + break + end + end + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +if not parser.success and not parser.throw_label then + parser.success = true + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + rules["VarArg"](parser) + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["FnArgs"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- choice with 2 alternatives + do -- sequence with 6 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + -- match single character "(" +if byte(parser.input, parser.pos + 1) == 40 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +if parser.success then +do -- zero or more repetitions + while true do + rules["SpaceBreak"](parser) + if not parser.success then + break + end + end + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end +end +end +if parser.success then +do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + rules["FnArgsExpList"](parser) + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end +if parser.success then +do -- zero or more repetitions + while true do + rules["SpaceBreak"](parser) + if not parser.success then + break + end + end + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end +end +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match single character ")" +if byte(parser.input, parser.pos + 1) == 41 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +if not parser.success and not parser.throw_label then + parser.success = true + do -- sequence with 4 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +-- match single character "!" +if byte(parser.input, parser.pos + 1) == 33 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + -- match single character "=" +if byte(parser.input, parser.pos + 1) == 61 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end +if parser.success then +do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + -- match literal "" +if sub(parser.input, parser.pos + 1, parser.pos + 0) == "" then + parser.pos = parser.pos + 0 +else + parser.success = false + record_furthest(parser) + +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["FnArgsDef"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- choice with 2 alternatives + do -- sequence with 8 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +-- match single character "(" +if byte(parser.input, parser.pos + 1) == 40 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end +if parser.success then +rules["White"](parser) +end +if parser.success then +do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + rules["FnArgDefList"](parser) + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end +if parser.success then +do -- choice with 2 alternatives + do -- sequence with 4 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +-- match literal "using" +if sub(parser.input, parser.pos + 1, parser.pos + 5) == "using" then + parser.pos = parser.pos + 5 +else + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character range "az,AZ,09,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 48 and rb <= 57) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end +if parser.success then +do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- choice with 2 alternatives + rules["NameList"](parser) +if not parser.success and not parser.throw_label then + parser.success = true + do -- sequence with 2 patterns + local pp_pos = parser.pos + rules["Space"](parser) +if parser.success then +-- match literal "nil" +if sub(parser.input, parser.pos + 1, parser.pos + 3) == "nil" then + parser.pos = parser.pos + 3 +else + parser.success = false + record_furthest(parser) + +end +end + if not parser.success then + parser.pos = pp_pos + end +end +end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +if not parser.success and not parser.throw_label then + parser.success = true + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + -- match literal "" +if sub(parser.input, parser.pos + 1, parser.pos + 0) == "" then + parser.pos = parser.pos + 0 +else + parser.success = false + record_furthest(parser) + +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end +end +end +if parser.success then +rules["White"](parser) +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match single character ")" +if byte(parser.input, parser.pos + 1) == 41 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +if not parser.success and not parser.throw_label then + parser.success = true + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + -- match literal "" +if sub(parser.input, parser.pos + 1, parser.pos + 0) == "" then + parser.pos = parser.pos + 0 +else + parser.success = false + record_furthest(parser) + +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +if parser.success then +do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + -- match literal "" +if sub(parser.input, parser.pos + 1, parser.pos + 0) == "" then + parser.pos = parser.pos + 0 +else + parser.success = false + record_furthest(parser) + +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["FnArgsExpList"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Exp"](parser) +if parser.success then +do -- zero or more repetitions + while true do + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- choice with 2 alternatives + rules["Break"](parser) +if not parser.success and not parser.throw_label then + parser.success = true + do -- sequence with 2 patterns + local pp_pos = parser.pos + rules["Space"](parser) +if parser.success then +-- match single character "," +if byte(parser.input, parser.pos + 1) == 44 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end + if not parser.success then + parser.pos = pp_pos + end +end +end +end +if parser.success then +rules["White"](parser) +end +if parser.success then +rules["Exp"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if not parser.success then + break + end + end + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["For"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 12 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "for", 0, 0) +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match literal "for" +if sub(parser.input, parser.pos + 1, parser.pos + 3) == "for" then + parser.pos = parser.pos + 3 +else + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character range "az,AZ,09,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 48 and rb <= 57) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end +if parser.success then +-- indenter cpush (stack 1): push constant 0 +ind_push(parser, 2, 0) +end +if parser.success then +rules["Name"](parser) +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match single character "=" +if byte(parser.input, parser.pos + 1) == 61 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end +if parser.success then +do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 5 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Exp"](parser) +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match single character "," +if byte(parser.input, parser.pos + 1) == 44 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end +if parser.success then +rules["Exp"](parser) +end +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +-- match single character "," +if byte(parser.input, parser.pos + 1) == 44 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end +if parser.success then +rules["Exp"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end +if parser.success then +-- indenter pop (stack 1) +if not ind_pop(parser, 2) then + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + do -- sequence with 3 patterns + local pp_pos = parser.pos + rules["Space"](parser) +if parser.success then +-- match literal "do" +if sub(parser.input, parser.pos + 1, parser.pos + 2) == "do" then + parser.pos = parser.pos + 2 +else + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character range "az,AZ,09,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 48 and rb <= 57) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end + if not parser.success then + parser.pos = pp_pos + end +end + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end +if parser.success then +rules["Body"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["ForEach"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 13 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "foreach", 0, 0) +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match literal "for" +if sub(parser.input, parser.pos + 1, parser.pos + 3) == "for" then + parser.pos = parser.pos + 3 +else + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character range "az,AZ,09,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 48 and rb <= 57) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end +if parser.success then +do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + rules["AssignableNameList"](parser) + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match literal "in" +if sub(parser.input, parser.pos + 1, parser.pos + 2) == "in" then + parser.pos = parser.pos + 2 +else + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character range "az,AZ,09,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 48 and rb <= 57) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end +if parser.success then +-- indenter cpush (stack 1): push constant 0 +ind_push(parser, 2, 0) +end +if parser.success then +do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- choice with 2 alternatives + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +-- match single character "*" +if byte(parser.input, parser.pos + 1) == 42 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end +if parser.success then +do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "unpack", 0, 0) +end +if parser.success then +rules["Exp"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +if not parser.success and not parser.throw_label then + parser.success = true + rules["ExpList"](parser) +end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end +if parser.success then +-- indenter pop (stack 1) +if not ind_pop(parser, 2) then + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + do -- sequence with 3 patterns + local pp_pos = parser.pos + rules["Space"](parser) +if parser.success then +-- match literal "do" +if sub(parser.input, parser.pos + 1, parser.pos + 2) == "do" then + parser.pos = parser.pos + 2 +else + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character range "az,AZ,09,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 48 and rb <= 57) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end + if not parser.success then + parser.pos = pp_pos + end +end + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end +if parser.success then +rules["Body"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["FunLit"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 4 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "fndef", 0, 0) +end +if parser.success then +rules["FnArgsDef"](parser) +end +if parser.success then +do -- choice with 2 alternatives + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +-- match literal "->" +if sub(parser.input, parser.pos + 1, parser.pos + 2) == "->" then + parser.pos = parser.pos + 2 +else + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "slim", 0, 0) +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +if not parser.success and not parser.throw_label then + parser.success = true + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +-- match literal "=>" +if sub(parser.input, parser.pos + 1, parser.pos + 2) == "=>" then + parser.pos = parser.pos + 2 +else + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "fat", 0, 0) +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +end +end +end +if parser.success then +do -- choice with 2 alternatives + rules["Body"](parser) +if not parser.success and not parser.throw_label then + parser.success = true + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + -- match literal "" +if sub(parser.input, parser.pos + 1, parser.pos + 0) == "" then + parser.pos = parser.pos + 0 +else + parser.success = false + record_furthest(parser) + +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["If"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 9 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "if", 0, 0) +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match literal "if" +if sub(parser.input, parser.pos + 1, parser.pos + 2) == "if" then + parser.pos = parser.pos + 2 +else + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character range "az,AZ,09,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 48 and rb <= 57) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end +if parser.success then +rules["IfCond"](parser) +end +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + do -- sequence with 3 patterns + local pp_pos = parser.pos + rules["Space"](parser) +if parser.success then +-- match literal "then" +if sub(parser.input, parser.pos + 1, parser.pos + 4) == "then" then + parser.pos = parser.pos + 4 +else + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character range "az,AZ,09,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 48 and rb <= 57) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end + if not parser.success then + parser.pos = pp_pos + end +end + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end +if parser.success then +rules["Body"](parser) +end +if parser.success then +do -- zero or more repetitions + while true do + rules["IfElseIf"](parser) + if not parser.success then + break + end + end + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end +end +end +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + rules["IfElse"](parser) + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["IfCond"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- transform capture (Cfn id=0) + local fn_cap_start = parser.cap_n + cap_push(parser, CAP_FN_OPEN, cmt_fns[0], parser.pos, 0) + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Exp"](parser) +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + rules["Assign"](parser) + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_FN_CLOSE, nil, parser.pos, 0) + else + parser.cap_n = fn_cap_start + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["IfElse"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 6 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "else", 0, 0) +end +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Break"](parser) +if parser.success then +do -- zero or more repetitions + while true do + rules["EmptyLine"](parser) + if not parser.success then + break + end + end + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end +end +end +if parser.success then +rules["CheckIndent"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match literal "else" +if sub(parser.input, parser.pos + 1, parser.pos + 4) == "else" then + parser.pos = parser.pos + 4 +else + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character range "az,AZ,09,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 48 and rb <= 57) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end +if parser.success then +rules["Body"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["IfElseIf"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 8 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "elseif", 0, 0) +end +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Break"](parser) +if parser.success then +do -- zero or more repetitions + while true do + rules["EmptyLine"](parser) + if not parser.success then + break + end + end + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end +end +end +if parser.success then +rules["CheckIndent"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match literal "elseif" +if sub(parser.input, parser.pos + 1, parser.pos + 6) == "elseif" then + parser.pos = parser.pos + 6 +else + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character range "az,AZ,09,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 48 and rb <= 57) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end +if parser.success then +do -- transform capture (Cfn id=2) + local fn_cap_start = parser.cap_n + cap_push(parser, CAP_FN_OPEN, cmt_fns[2], parser.pos, 0) + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + cap_push(parser, CAP_POS, nil, parser.pos, 0) -- position capture +if parser.success then +rules["IfCond"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_FN_CLOSE, nil, parser.pos, 0) + else + parser.cap_n = fn_cap_start + end +end +end +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + do -- sequence with 3 patterns + local pp_pos = parser.pos + rules["Space"](parser) +if parser.success then +-- match literal "then" +if sub(parser.input, parser.pos + 1, parser.pos + 4) == "then" then + parser.pos = parser.pos + 4 +else + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character range "az,AZ,09,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 48 and rb <= 57) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end + if not parser.success then + parser.pos = pp_pos + end +end + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end +if parser.success then +rules["Body"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["Import"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 10 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "import", 0, 0) +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match literal "import" +if sub(parser.input, parser.pos + 1, parser.pos + 6) == "import" then + parser.pos = parser.pos + 6 +else + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character range "az,AZ,09,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 48 and rb <= 57) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end +if parser.success then +do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + rules["ImportNameList"](parser) + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end +if parser.success then +do -- zero or more repetitions + while true do + rules["SpaceBreak"](parser) + if not parser.success then + break + end + end + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end +end +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match literal "from" +if sub(parser.input, parser.pos + 1, parser.pos + 4) == "from" then + parser.pos = parser.pos + 4 +else + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character range "az,AZ,09,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 48 and rb <= 57) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end +if parser.success then +rules["Exp"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["ImportName"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- choice with 2 alternatives + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +-- match single character "\\" +if byte(parser.input, parser.pos + 1) == 92 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end +if parser.success then +do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "colon", 0, 0) +end +if parser.success then +rules["Name"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +if not parser.success and not parser.throw_label then + parser.success = true + rules["Name"](parser) +end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["ImportNameList"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- zero or more repetitions + while true do + rules["SpaceBreak"](parser) + if not parser.success then + break + end + end + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end +end +if parser.success then +rules["ImportName"](parser) +end +if parser.success then +do -- zero or more repetitions + while true do + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- choice with 2 alternatives + do -- at least 1 repetitions + local pp_pos = parser.pos + local rep_count = 0 + while true do + rules["SpaceBreak"](parser) + if not parser.success then + break + end + rep_count = rep_count + 1 + end + if parser.throw_label then + -- Keep failure state, propagate labeled failure + elseif rep_count >= 1 then + parser.success = true + else + parser.pos = pp_pos + + end +end +if not parser.success and not parser.throw_label then + parser.success = true + do -- sequence with 3 patterns + local pp_pos = parser.pos + rules["Space"](parser) +if parser.success then +-- match single character "," +if byte(parser.input, parser.pos + 1) == 44 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end +if parser.success then +do -- zero or more repetitions + while true do + rules["SpaceBreak"](parser) + if not parser.success then + break + end + end + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end +end +end + if not parser.success then + parser.pos = pp_pos + end +end +end +end +if parser.success then +rules["ImportName"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if not parser.success then + break + end + end + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["InBlock"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Advance"](parser) +if parser.success then +rules["Block"](parser) +end +if parser.success then +rules["PopIndent"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["Invoke"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- FIRST-byte dispatched ordered choice + local dd = disp[4] + local db = byte(parser.input, parser.pos + 1) + local dm = db and dd.bytes[db] or dd.eof + parser.success = false + if not parser.success and not parser.throw_label and dm[1] then + parser.success = true + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "call", 0, 0) +end +if parser.success then +rules["FnArgs"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end +if not parser.success and not parser.throw_label and dm[2] then + if dm.s[2] then record_furthest(parser) end + parser.success = true + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "call", 0, 0) +end +if parser.success then +do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + rules["SingleString"](parser) + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end +if not parser.success and not parser.throw_label and dm[3] then + if dm.s[3] then record_furthest(parser) end + parser.success = true + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "call", 0, 0) +end +if parser.success then +do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + rules["DoubleString"](parser) + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end +if not parser.success and not parser.throw_label and dm[4] then + if dm.s[4] then record_furthest(parser) end + parser.success = true + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- lookahead (match without consuming input) + local pp_pos = parser.pos + -- match single character "[" +if byte(parser.input, parser.pos + 1) == 91 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end + if parser.success then + parser.pos = pp_pos + end +end +if parser.success then +do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "call", 0, 0) +end +if parser.success then +do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + rules["LuaString"](parser) + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +end + if not parser.success and not parser.throw_label then + record_furthest(parser) + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["InvokeArgs"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- negate (only match if pattern fails) + local pp_pos = parser.pos + -- match single character "-" +if byte(parser.input, parser.pos + 1) == 45 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +if parser.success then +do -- choice with 2 alternatives + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["ExpList"](parser) +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + do -- choice with 2 alternatives + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +-- match single character "," +if byte(parser.input, parser.pos + 1) == 44 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end +if parser.success then +do -- choice with 2 alternatives + rules["TableBlock"](parser) +if not parser.success and not parser.throw_label then + parser.success = true + do -- sequence with 4 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["SpaceBreak"](parser) +if parser.success then +rules["Advance"](parser) +end +if parser.success then +rules["ArgBlock"](parser) +end +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + rules["TableBlock"](parser) + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +if not parser.success and not parser.throw_label then + parser.success = true + rules["TableBlock"](parser) +end +end + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +if not parser.success and not parser.throw_label then + parser.success = true + rules["TableBlock"](parser) +end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["KeyName"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- choice with 2 alternatives + rules["SelfName"](parser) +if not parser.success and not parser.throw_label then + parser.success = true + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "key_literal", 0, 0) +end +if parser.success then +rules["NameRaw"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["KeyValue"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- choice with 2 alternatives + do -- transform capture (Cfn id=4) + local fn_cap_start = parser.cap_n + cap_push(parser, CAP_FN_OPEN, cmt_fns[4], parser.pos, 0) + do -- sequence with 5 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +-- match single character ":" +if byte(parser.input, parser.pos + 1) == 58 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + rules["SomeSpace"](parser) + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end +if parser.success then +rules["Name"](parser) +end +if parser.success then +cap_push(parser, CAP_POS, nil, parser.pos, 0) -- position capture +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_FN_CLOSE, nil, parser.pos, 0) + else + parser.cap_n = fn_cap_start + end +end +if not parser.success and not parser.throw_label then + parser.success = true + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- FIRST-byte dispatched ordered choice + local dd = disp[5] + local db = byte(parser.input, parser.pos + 1) + local dm = db and dd.bytes[db] or dd.eof + parser.success = false + if not parser.success and not parser.throw_label and dm[1] then + parser.success = true + rules["KeyName"](parser) +end +if not parser.success and not parser.throw_label and dm[2] then + if dm.s[2] then record_furthest(parser) end + parser.success = true + do -- sequence with 5 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +-- match single character "[" +if byte(parser.input, parser.pos + 1) == 91 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end +if parser.success then +rules["Exp"](parser) +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match single character "]" +if byte(parser.input, parser.pos + 1) == 93 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +end +if not parser.success and not parser.throw_label and dm[3] then + if dm.s[3] then record_furthest(parser) end + parser.success = true + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +rules["DoubleString"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +end +if not parser.success and not parser.throw_label and dm[4] then + if dm.s[4] then record_furthest(parser) end + parser.success = true + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +rules["SingleString"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +end + if not parser.success and not parser.throw_label then + record_furthest(parser) + end +end +if parser.success then +-- match single character ":" +if byte(parser.input, parser.pos + 1) == 58 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end +if parser.success then +do -- choice with 3 alternatives + rules["Exp"](parser) +if not parser.success and not parser.throw_label then + parser.success = true + rules["TableBlock"](parser) +end +if not parser.success and not parser.throw_label then + parser.success = true + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- at least 1 repetitions + local pp_pos = parser.pos + local rep_count = 0 + while true do + rules["SpaceBreak"](parser) + if not parser.success then + break + end + rep_count = rep_count + 1 + end + if parser.throw_label then + -- Keep failure state, propagate labeled failure + elseif rep_count >= 1 then + parser.success = true + else + parser.pos = pp_pos + + end +end +if parser.success then +rules["Exp"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["KeyValueLine"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["CheckIndent"](parser) +if parser.success then +rules["KeyValueList"](parser) +end +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + do -- sequence with 2 patterns + local pp_pos = parser.pos + rules["Space"](parser) +if parser.success then +-- match single character "," +if byte(parser.input, parser.pos + 1) == 44 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end + if not parser.success then + parser.pos = pp_pos + end +end + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["KeyValueList"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["KeyValue"](parser) +if parser.success then +do -- zero or more repetitions + while true do + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +-- match single character "," +if byte(parser.input, parser.pos + 1) == 44 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end +if parser.success then +rules["KeyValue"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if not parser.success then + break + end + end + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["Line"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- choice with 2 alternatives + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["CheckIndent"](parser) +if parser.success then +rules["Statement"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +if not parser.success and not parser.throw_label then + parser.success = true + do -- sequence with 2 patterns + local pp_pos = parser.pos + rules["Space"](parser) +if parser.success then +do -- lookahead (match without consuming input) + local pp_pos = parser.pos + rules["Stop"](parser) + if parser.success then + parser.pos = pp_pos + end +end +end + if not parser.success then + parser.pos = pp_pos + end +end +end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["Local"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- sequence with 4 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +-- match literal "local" +if sub(parser.input, parser.pos + 1, parser.pos + 5) == "local" then + parser.pos = parser.pos + 5 +else + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character range "az,AZ,09,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 48 and rb <= 57) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end +if parser.success then +do -- choice with 2 alternatives + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "declare_glob", 0, 0) +end +if parser.success then +do -- choice with 2 alternatives + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +do -- capture + local cap_start_pos = parser.pos + -- match single character "*" +if byte(parser.input, parser.pos + 1) == 42 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end + if parser.success then + cap_push(parser, CAP_STR, nil, cap_start_pos, parser.pos - cap_start_pos) + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +if not parser.success and not parser.throw_label then + parser.success = true + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +do -- capture + local cap_start_pos = parser.pos + -- match single character "^" +if byte(parser.input, parser.pos + 1) == 94 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end + if parser.success then + cap_push(parser, CAP_STR, nil, cap_start_pos, parser.pos - cap_start_pos) + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +if not parser.success and not parser.throw_label then + parser.success = true + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "declare_with_shadows", 0, 0) +end +if parser.success then +do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + rules["NameList"](parser) + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["LuaString"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- transform capture (Cfn id=7) + local fn_cap_start = parser.cap_n + cap_push(parser, CAP_FN_OPEN, cmt_fns[7], parser.pos, 0) + do -- sequence with 9 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +-- match single character "[" +if byte(parser.input, parser.pos + 1) == 91 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end +if parser.success then +cap_push(parser, CAP_POS, nil, parser.pos, 0) -- position capture +end +if parser.success then +do -- capture group "lua_eq" + local cg_cap_start = parser.cap_n + cap_push(parser, CAP_GROUP_OPEN, "lua_eq", parser.pos, 0) + do -- zero or more repetitions + while true do + -- match single character "=" +if byte(parser.input, parser.pos + 1) == 61 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end + if not parser.success then + break + end + end + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end +end + if parser.success then + cap_push(parser, CAP_GROUP_CLOSE, "lua_eq", parser.pos, 0) + else + parser.cap_n = cg_cap_start + end +end +end +if parser.success then +cap_push(parser, CAP_POS, nil, parser.pos, 0) -- position capture +end +if parser.success then +-- match single character "[" +if byte(parser.input, parser.pos + 1) == 91 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + rules["Break"](parser) + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end +if parser.success then +do -- capture + local cap_start_pos = parser.pos + do -- zero or more repetitions + while true do + do -- sequence with 2 patterns + local pp_pos = parser.pos + do -- negate (only match if pattern fails) + local pp_pos = parser.pos + rules["LuaStringClose"](parser) + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +if parser.success then +-- match any 1 characters +if parser.pos + 1 <= parser.input_len then + parser.pos = parser.pos + 1 +else + parser.success = false + record_furthest(parser) + +end +end + if not parser.success then + parser.pos = pp_pos + end +end + if not parser.success then + break + end + end + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end +end + if parser.success then + cap_push(parser, CAP_STR, nil, cap_start_pos, parser.pos - cap_start_pos) + end +end +end +if parser.success then +rules["LuaStringClose"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_FN_CLOSE, nil, parser.pos, 0) + else + parser.cap_n = fn_cap_start + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["LuaStringClose"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- sequence with 3 patterns + local pp_pos = parser.pos + -- match single character "]" +if byte(parser.input, parser.pos + 1) == 93 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +if parser.success then +-- capture match back "lua_eq" +parser.success = cap_match_back(parser, "lua_eq") +if not parser.success then + record_furthest(parser) + +end +end +if parser.success then +-- match single character "]" +if byte(parser.input, parser.pos + 1) == 93 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end + if not parser.success then + parser.pos = pp_pos + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["Name"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- sequence with 2 patterns + local pp_pos = parser.pos + do -- trie match for: "continue", "extends", "elseif", "export", "import", "return", "switch", "unless", "break", "class", "local", "using", "while", "else", "from", "then", "when", "with", "and", "for", "not", "do", "if", "in", "or" + local trie_pos = parser.pos + local last_terminal_pos = 0 + local has_terminal = false + local tb = byte(parser.input, parser.pos + 1) +if tb == 97 then -- "a" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 110 then -- "n" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 100 then -- "d" + parser.pos = parser.pos + 1 +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +elseif tb == 98 then -- "b" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 114 then -- "r" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 101 then -- "e" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 97 then -- "a" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 107 then -- "k" + parser.pos = parser.pos + 1 +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +elseif tb == 99 then -- "c" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 108 then -- "l" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 97 then -- "a" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 115 then -- "s" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 115 then -- "s" + parser.pos = parser.pos + 1 +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +elseif tb == 111 then -- "o" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 110 then -- "n" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 116 then -- "t" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 105 then -- "i" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 110 then -- "n" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 117 then -- "u" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 101 then -- "e" + parser.pos = parser.pos + 1 +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +elseif tb == 100 then -- "d" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 111 then -- "o" + parser.pos = parser.pos + 1 +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +elseif tb == 101 then -- "e" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 108 then -- "l" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 115 then -- "s" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 101 then -- "e" + parser.pos = parser.pos + 1 +if not has_terminal or parser.pos > last_terminal_pos then + last_terminal_pos = parser.pos + has_terminal = true +end +local tb = byte(parser.input, parser.pos + 1) +if tb == 105 then -- "i" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 102 then -- "f" + parser.pos = parser.pos + 1 +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +if not parser.success then + -- partial match is valid: "else" + parser.success = true +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +elseif tb == 120 then -- "x" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 112 then -- "p" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 111 then -- "o" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 114 then -- "r" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 116 then -- "t" + parser.pos = parser.pos + 1 +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +elseif tb == 116 then -- "t" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 101 then -- "e" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 110 then -- "n" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 100 then -- "d" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 115 then -- "s" + parser.pos = parser.pos + 1 +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +elseif tb == 102 then -- "f" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 111 then -- "o" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 114 then -- "r" + parser.pos = parser.pos + 1 +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +elseif tb == 114 then -- "r" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 111 then -- "o" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 109 then -- "m" + parser.pos = parser.pos + 1 +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +elseif tb == 105 then -- "i" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 102 then -- "f" + parser.pos = parser.pos + 1 +elseif tb == 109 then -- "m" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 112 then -- "p" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 111 then -- "o" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 114 then -- "r" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 116 then -- "t" + parser.pos = parser.pos + 1 +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +elseif tb == 110 then -- "n" + parser.pos = parser.pos + 1 +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +elseif tb == 108 then -- "l" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 111 then -- "o" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 99 then -- "c" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 97 then -- "a" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 108 then -- "l" + parser.pos = parser.pos + 1 +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +elseif tb == 110 then -- "n" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 111 then -- "o" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 116 then -- "t" + parser.pos = parser.pos + 1 +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +elseif tb == 111 then -- "o" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 114 then -- "r" + parser.pos = parser.pos + 1 +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +elseif tb == 114 then -- "r" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 101 then -- "e" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 116 then -- "t" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 117 then -- "u" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 114 then -- "r" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 110 then -- "n" + parser.pos = parser.pos + 1 +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +elseif tb == 115 then -- "s" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 119 then -- "w" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 105 then -- "i" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 116 then -- "t" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 99 then -- "c" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 104 then -- "h" + parser.pos = parser.pos + 1 +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +elseif tb == 116 then -- "t" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 104 then -- "h" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 101 then -- "e" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 110 then -- "n" + parser.pos = parser.pos + 1 +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +elseif tb == 117 then -- "u" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 110 then -- "n" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 108 then -- "l" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 101 then -- "e" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 115 then -- "s" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 115 then -- "s" + parser.pos = parser.pos + 1 +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +elseif tb == 115 then -- "s" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 105 then -- "i" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 110 then -- "n" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 103 then -- "g" + parser.pos = parser.pos + 1 +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +elseif tb == 119 then -- "w" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 104 then -- "h" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 101 then -- "e" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 110 then -- "n" + parser.pos = parser.pos + 1 +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +elseif tb == 105 then -- "i" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 108 then -- "l" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 101 then -- "e" + parser.pos = parser.pos + 1 +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +elseif tb == 105 then -- "i" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 116 then -- "t" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 104 then -- "h" + parser.pos = parser.pos + 1 +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end + if not parser.success then + parser.pos = trie_pos + end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character range "az,AZ,09,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 48 and rb <= 57) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end + if not parser.success then + parser.pos = pp_pos + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end +if parser.success then +rules["NameRaw"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["NameList"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Name"](parser) +if parser.success then +do -- zero or more repetitions + while true do + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +-- match single character "," +if byte(parser.input, parser.pos + 1) == 44 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end +if parser.success then +rules["Name"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if not parser.success then + break + end + end + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["NameOrDestructure"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- choice with 2 alternatives + rules["Name"](parser) +if not parser.success and not parser.throw_label then + parser.success = true + rules["TableLit"](parser) +end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["NameRaw"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- capture + local cap_start_pos = parser.pos + do -- sequence with 2 patterns + local pp_pos = parser.pos + do -- match character range "az,AZ,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end +if parser.success then +do -- zero or more repetitions + while true do + do -- match character range "az,AZ,09,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 48 and rb <= 57) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if not parser.success then + break + end + end + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end +end +end + if not parser.success then + parser.pos = pp_pos + end +end + if parser.success then + cap_push(parser, CAP_STR, nil, cap_start_pos, parser.pos - cap_start_pos) + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["Num"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "number", 0, 0) +end +if parser.success then +do -- capture + local cap_start_pos = parser.pos + do -- choice with 3 alternatives + do -- sequence with 3 patterns + local pp_pos = parser.pos + -- match literal "0x" +if sub(parser.input, parser.pos + 1, parser.pos + 2) == "0x" then + parser.pos = parser.pos + 2 +else + parser.success = false + record_furthest(parser) + +end +if parser.success then +do -- at least 1 repetitions + local pp_pos = parser.pos + local rep_count = 0 + while true do + do -- match character range "09,af,AF" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 48 and rb <= 57) or (rb >= 97 and rb <= 102) or (rb >= 65 and rb <= 70)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if not parser.success then + break + end + rep_count = rep_count + 1 + end + if parser.throw_label then + -- Keep failure state, propagate labeled failure + elseif rep_count >= 1 then + parser.success = true + else + parser.pos = pp_pos + + end +end +end +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + do -- sequence with 2 patterns + local pp_pos = parser.pos + do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + do -- match character set "uU" + local sb = byte(parser.input, parser.pos + 1) + if sb and sets[4][sb] then + parser.pos = parser.pos + 1 + else + parser.success = false + end +end + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +if parser.success then +do -- at least 2 repetitions + local pp_pos = parser.pos + local rep_count = 0 + while true do + do -- match character set "lL" + local sb = byte(parser.input, parser.pos + 1) + if sb and sets[5][sb] then + parser.pos = parser.pos + 1 + else + parser.success = false + end +end + if not parser.success then + break + end + rep_count = rep_count + 1 + end + if parser.throw_label then + -- Keep failure state, propagate labeled failure + elseif rep_count >= 2 then + parser.success = true + else + parser.pos = pp_pos + + end +end +end + if not parser.success then + parser.pos = pp_pos + end +end + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end + if not parser.success then + parser.pos = pp_pos + end +end +if not parser.success and not parser.throw_label then + parser.success = true + do -- sequence with 3 patterns + local pp_pos = parser.pos + do -- at least 1 repetitions + local pp_pos = parser.pos + local rep_count = 0 + while true do + do -- match character range "09" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 48 and rb <= 57)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if not parser.success then + break + end + rep_count = rep_count + 1 + end + if parser.throw_label then + -- Keep failure state, propagate labeled failure + elseif rep_count >= 1 then + parser.success = true + else + parser.pos = pp_pos + + end +end +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + do -- match character set "uU" + local sb = byte(parser.input, parser.pos + 1) + if sb and sets[4][sb] then + parser.pos = parser.pos + 1 + else + parser.success = false + end +end + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end +if parser.success then +do -- at least 2 repetitions + local pp_pos = parser.pos + local rep_count = 0 + while true do + do -- match character set "lL" + local sb = byte(parser.input, parser.pos + 1) + if sb and sets[5][sb] then + parser.pos = parser.pos + 1 + else + parser.success = false + end +end + if not parser.success then + break + end + rep_count = rep_count + 1 + end + if parser.throw_label then + -- Keep failure state, propagate labeled failure + elseif rep_count >= 2 then + parser.success = true + else + parser.pos = pp_pos + + end +end +end + if not parser.success then + parser.pos = pp_pos + end +end +end +if not parser.success and not parser.throw_label then + parser.success = true + do -- sequence with 2 patterns + local pp_pos = parser.pos + do -- choice with 2 alternatives + do -- sequence with 2 patterns + local pp_pos = parser.pos + do -- at least 1 repetitions + local pp_pos = parser.pos + local rep_count = 0 + while true do + do -- match character range "09" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 48 and rb <= 57)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if not parser.success then + break + end + rep_count = rep_count + 1 + end + if parser.throw_label then + -- Keep failure state, propagate labeled failure + elseif rep_count >= 1 then + parser.success = true + else + parser.pos = pp_pos + + end +end +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + do -- sequence with 2 patterns + local pp_pos = parser.pos + -- match single character "." +if byte(parser.input, parser.pos + 1) == 46 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +if parser.success then +do -- at least 1 repetitions + local pp_pos = parser.pos + local rep_count = 0 + while true do + do -- match character range "09" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 48 and rb <= 57)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if not parser.success then + break + end + rep_count = rep_count + 1 + end + if parser.throw_label then + -- Keep failure state, propagate labeled failure + elseif rep_count >= 1 then + parser.success = true + else + parser.pos = pp_pos + + end +end +end + if not parser.success then + parser.pos = pp_pos + end +end + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end + if not parser.success then + parser.pos = pp_pos + end +end +if not parser.success and not parser.throw_label then + parser.success = true + do -- sequence with 2 patterns + local pp_pos = parser.pos + -- match single character "." +if byte(parser.input, parser.pos + 1) == 46 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +if parser.success then +do -- at least 1 repetitions + local pp_pos = parser.pos + local rep_count = 0 + while true do + do -- match character range "09" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 48 and rb <= 57)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if not parser.success then + break + end + rep_count = rep_count + 1 + end + if parser.throw_label then + -- Keep failure state, propagate labeled failure + elseif rep_count >= 1 then + parser.success = true + else + parser.pos = pp_pos + + end +end +end + if not parser.success then + parser.pos = pp_pos + end +end +end +end +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + do -- sequence with 3 patterns + local pp_pos = parser.pos + do -- match character set "eE" + local sb = byte(parser.input, parser.pos + 1) + if sb and sets[6][sb] then + parser.pos = parser.pos + 1 + else + parser.success = false + end +end +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + -- match single character "-" +if byte(parser.input, parser.pos + 1) == 45 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end +if parser.success then +do -- at least 1 repetitions + local pp_pos = parser.pos + local rep_count = 0 + while true do + do -- match character range "09" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 48 and rb <= 57)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if not parser.success then + break + end + rep_count = rep_count + 1 + end + if parser.throw_label then + -- Keep failure state, propagate labeled failure + elseif rep_count >= 1 then + parser.success = true + else + parser.pos = pp_pos + + end +end +end + if not parser.success then + parser.pos = pp_pos + end +end + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end + if not parser.success then + parser.pos = pp_pos + end +end +end +end + if parser.success then + cap_push(parser, CAP_STR, nil, cap_start_pos, parser.pos - cap_start_pos) + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["Parens"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- sequence with 7 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +-- match single character "(" +if byte(parser.input, parser.pos + 1) == 40 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end +if parser.success then +do -- zero or more repetitions + while true do + rules["SpaceBreak"](parser) + if not parser.success then + break + end + end + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end +end +end +if parser.success then +rules["Exp"](parser) +end +if parser.success then +do -- zero or more repetitions + while true do + rules["SpaceBreak"](parser) + if not parser.success then + break + end + end + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end +end +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match single character ")" +if byte(parser.input, parser.pos + 1) == 41 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["PopIndent"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + -- indenter pop (stack 0) +if not ind_pop(parser, 1) then + parser.success = false + record_furthest(parser) + +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["PreventIndent"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + -- indenter prevent (stack 0): push sentinel so nested advance fails +ind_push(parser, 1, IND_PREVENT) + + parser.depth = depth - 1 + return parser.success +end + + +rules["PushIndent"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- indenter push (stack 0): consume whitespace, push measured width + local ind_width, ind_end = ind_measure(parser, 4) + ind_push(parser, 1, ind_width) + parser.pos = ind_end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["Return"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 5 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "return", 0, 0) +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match literal "return" +if sub(parser.input, parser.pos + 1, parser.pos + 6) == "return" then + parser.pos = parser.pos + 6 +else + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character range "az,AZ,09,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 48 and rb <= 57) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end +if parser.success then +do -- choice with 2 alternatives + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "explist", 0, 0) +end +if parser.success then +rules["ExpListLow"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +if not parser.success and not parser.throw_label then + parser.success = true + do -- capture + local cap_start_pos = parser.pos + -- match literal "" +if sub(parser.input, parser.pos + 1, parser.pos + 0) == "" then + parser.pos = parser.pos + 0 +else + parser.success = false + record_furthest(parser) + +end + if parser.success then + cap_push(parser, CAP_STR, nil, cap_start_pos, parser.pos - cap_start_pos) + end +end +end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["SelfName"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +-- match single character "@" +if byte(parser.input, parser.pos + 1) == 64 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end +if parser.success then +do -- choice with 3 alternatives + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + -- match single character "@" +if byte(parser.input, parser.pos + 1) == 64 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +if parser.success then +do -- choice with 2 alternatives + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "self_class", 0, 0) +end +if parser.success then +rules["NameRaw"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +if not parser.success and not parser.throw_label then + parser.success = true + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "self.__class", 0, 0) +end +end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +if not parser.success and not parser.throw_label then + parser.success = true + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "self", 0, 0) +end +if parser.success then +rules["NameRaw"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end +if not parser.success and not parser.throw_label then + parser.success = true + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "self", 0, 0) +end +end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["Shebang"] = function(parser) + local start = parser.pos + -- Position-pure rule: a single-slot memo short-circuits the repeated + -- calls that backtracking alternatives make at the same position + if parser.memo_pos[5] == start + 1 then + local memo_end = parser.memo_end[5] + if memo_end == -1 then + parser.success = false + return false + end + parser.pos = memo_end + parser.success = true + return true + end +local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- sequence with 2 patterns + local pp_pos = parser.pos + -- match literal "#!" +if sub(parser.input, parser.pos + 1, parser.pos + 2) == "#!" then + parser.pos = parser.pos + 2 +else + parser.success = false + record_furthest(parser) + +end +if parser.success then +do -- zero or more repetitions + while true do + do -- sequence with 2 patterns + local pp_pos = parser.pos + do -- negate (only match if pattern fails) + local pp_pos = parser.pos + rules["Stop"](parser) + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +if parser.success then +-- match any 1 characters +if parser.pos + 1 <= parser.input_len then + parser.pos = parser.pos + 1 +else + parser.success = false + record_furthest(parser) + +end +end + if not parser.success then + parser.pos = pp_pos + end +end + if not parser.success then + break + end + end + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end +end +end + if not parser.success then + parser.pos = pp_pos + end +end + parser.memo_pos[5] = start + 1 + parser.memo_end[5] = parser.success and parser.pos or -1 + + parser.depth = depth - 1 + return parser.success +end + + +rules["SimpleValue"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- FIRST-byte dispatched ordered choice + local dd = disp[6] + local db = byte(parser.input, parser.pos + 1) + local dm = db and dd.bytes[db] or dd.eof + parser.success = false + if not parser.success and not parser.throw_label and dm[1] then + parser.success = true + rules["If"](parser) +end +if not parser.success and not parser.throw_label and dm[2] then + if dm.s[2] then record_furthest(parser) end + parser.success = true + rules["Unless"](parser) +end +if not parser.success and not parser.throw_label and dm[3] then + if dm.s[3] then record_furthest(parser) end + parser.success = true + rules["Switch"](parser) +end +if not parser.success and not parser.throw_label and dm[4] then + if dm.s[4] then record_furthest(parser) end + parser.success = true + rules["With"](parser) +end +if not parser.success and not parser.throw_label and dm[5] then + if dm.s[5] then record_furthest(parser) end + parser.success = true + rules["ClassDecl"](parser) +end +if not parser.success and not parser.throw_label and dm[6] then + if dm.s[6] then record_furthest(parser) end + parser.success = true + rules["ForEach"](parser) +end +if not parser.success and not parser.throw_label and dm[7] then + if dm.s[7] then record_furthest(parser) end + parser.success = true + rules["For"](parser) +end +if not parser.success and not parser.throw_label and dm[8] then + if dm.s[8] then record_furthest(parser) end + parser.success = true + rules["While"](parser) +end +if not parser.success and not parser.throw_label and dm[9] then + if dm.s[9] then record_furthest(parser) end + parser.success = true + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- indenter ctop (stack 1): top ne 0 + local ind_s = parser.ind_stacks[2] + if not (ind_s.n > 0 and ind_s[ind_s.n] ~= 0) then + parser.success = false + record_furthest(parser) + + end +end +if parser.success then +rules["Do"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +end +if not parser.success and not parser.throw_label and dm[10] then + if dm.s[10] then record_furthest(parser) end + parser.success = true + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 5 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "minus", 0, 0) +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match single character "-" +if byte(parser.input, parser.pos + 1) == 45 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + rules["SomeSpace"](parser) + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end +if parser.success then +rules["Exp"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end +if not parser.success and not parser.throw_label and dm[11] then + if dm.s[11] then record_furthest(parser) end + parser.success = true + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 4 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "length", 0, 0) +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match single character "#" +if byte(parser.input, parser.pos + 1) == 35 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end +if parser.success then +rules["Exp"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end +if not parser.success and not parser.throw_label and dm[12] then + if dm.s[12] then record_furthest(parser) end + parser.success = true + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 4 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "bitnot", 0, 0) +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match single character "~" +if byte(parser.input, parser.pos + 1) == 126 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end +if parser.success then +rules["Exp"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end +if not parser.success and not parser.throw_label and dm[13] then + if dm.s[13] then record_furthest(parser) end + parser.success = true + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 5 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "not", 0, 0) +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match literal "not" +if sub(parser.input, parser.pos + 1, parser.pos + 3) == "not" then + parser.pos = parser.pos + 3 +else + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character range "az,AZ,09,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 48 and rb <= 57) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end +if parser.success then +rules["Exp"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end +if not parser.success and not parser.throw_label and dm[14] then + if dm.s[14] then record_furthest(parser) end + parser.success = true + rules["TblComprehension"](parser) +end +if not parser.success and not parser.throw_label and dm[15] then + if dm.s[15] then record_furthest(parser) end + parser.success = true + rules["TableLit"](parser) +end +if not parser.success and not parser.throw_label and dm[16] then + if dm.s[16] then record_furthest(parser) end + parser.success = true + rules["Comprehension"](parser) +end +if not parser.success and not parser.throw_label and dm[17] then + if dm.s[17] then record_furthest(parser) end + parser.success = true + rules["FunLit"](parser) +end +if not parser.success and not parser.throw_label and dm[18] then + if dm.s[18] then record_furthest(parser) end + parser.success = true + rules["Num"](parser) +end + if not parser.success and not parser.throw_label then + record_furthest(parser) + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["SingleString"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 4 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "string", 0, 0) +end +if parser.success then +do -- capture + local cap_start_pos = parser.pos + -- match single character "'" +if byte(parser.input, parser.pos + 1) == 39 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end + if parser.success then + cap_push(parser, CAP_STR, nil, cap_start_pos, parser.pos - cap_start_pos) + end +end +end +if parser.success then +do -- capture + local cap_start_pos = parser.pos + do -- zero or more repetitions + while true do + do -- choice with 3 alternatives + -- match literal "\\'" +if sub(parser.input, parser.pos + 1, parser.pos + 2) == "\\'" then + parser.pos = parser.pos + 2 +else + parser.success = false + record_furthest(parser) + +end +if not parser.success and not parser.throw_label then + parser.success = true + -- match literal "\\\\" +if sub(parser.input, parser.pos + 1, parser.pos + 2) == "\\\\" then + parser.pos = parser.pos + 2 +else + parser.success = false + record_furthest(parser) + +end +end +if not parser.success and not parser.throw_label then + parser.success = true + do -- sequence with 2 patterns + local pp_pos = parser.pos + do -- negate (only match if pattern fails) + local pp_pos = parser.pos + -- match single character "'" +if byte(parser.input, parser.pos + 1) == 39 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +if parser.success then +-- match any 1 characters +if parser.pos + 1 <= parser.input_len then + parser.pos = parser.pos + 1 +else + parser.success = false + record_furthest(parser) + +end +end + if not parser.success then + parser.pos = pp_pos + end +end +end +end + if not parser.success then + break + end + end + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end +end + if parser.success then + cap_push(parser, CAP_STR, nil, cap_start_pos, parser.pos - cap_start_pos) + end +end +end +if parser.success then +-- match single character "'" +if byte(parser.input, parser.pos + 1) == 39 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["Slice"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 9 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "slice", 0, 0) +end +if parser.success then +-- match single character "[" +if byte(parser.input, parser.pos + 1) == 91 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end +if parser.success then +do -- choice with 2 alternatives + rules["SliceValue"](parser) +if not parser.success and not parser.throw_label then + parser.success = true + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, 1, 0, 0) +end +end +end +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match single character "," +if byte(parser.input, parser.pos + 1) == 44 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end +if parser.success then +do -- choice with 2 alternatives + rules["SliceValue"](parser) +if not parser.success and not parser.throw_label then + parser.success = true + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "", 0, 0) +end +end +end +end +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +-- match single character "," +if byte(parser.input, parser.pos + 1) == 44 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end +if parser.success then +rules["SliceValue"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match single character "]" +if byte(parser.input, parser.pos + 1) == 93 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["SliceValue"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + rules["Exp"](parser) + + parser.depth = depth - 1 + return parser.success +end + + +rules["SomeSpace"] = function(parser) + local start = parser.pos + -- Position-pure rule: a single-slot memo short-circuits the repeated + -- calls that backtracking alternatives make at the same position + if parser.memo_pos[6] == start + 1 then + local memo_end = parser.memo_end[6] + if memo_end == -1 then + parser.success = false + return false + end + parser.pos = memo_end + parser.success = true + return true + end +local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- sequence with 2 patterns + local pp_pos = parser.pos + do -- at least 1 repetitions + local pp_pos = parser.pos + local rep_count = 0 + while true do + do -- match character set " \t" + local sb = byte(parser.input, parser.pos + 1) + if sb and sets[7][sb] then + parser.pos = parser.pos + 1 + else + parser.success = false + end +end + if not parser.success then + break + end + rep_count = rep_count + 1 + end + if parser.throw_label then + -- Keep failure state, propagate labeled failure + elseif rep_count >= 1 then + parser.success = true + else + parser.pos = pp_pos + + end +end +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + rules["Comment"](parser) + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end + if not parser.success then + parser.pos = pp_pos + end +end + parser.memo_pos[6] = start + 1 + parser.memo_end[6] = parser.success and parser.pos or -1 + + parser.depth = depth - 1 + return parser.success +end + + +rules["Space"] = function(parser) + local start = parser.pos + -- Position-pure rule: a single-slot memo short-circuits the repeated + -- calls that backtracking alternatives make at the same position + if parser.memo_pos[7] == start + 1 then + local memo_end = parser.memo_end[7] + if memo_end == -1 then + parser.success = false + return false + end + parser.pos = memo_end + parser.success = true + return true + end +local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- sequence with 2 patterns + local pp_pos = parser.pos + do -- zero or more repetitions + while true do + do -- match character set " \t" + local sb = byte(parser.input, parser.pos + 1) + if sb and sets[7][sb] then + parser.pos = parser.pos + 1 + else + parser.success = false + end +end + if not parser.success then + break + end + end + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end +end +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + rules["Comment"](parser) + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end + if not parser.success then + parser.pos = pp_pos + end +end + parser.memo_pos[7] = start + 1 + parser.memo_end[7] = parser.success and parser.pos or -1 + + parser.depth = depth - 1 + return parser.success +end + + +rules["SpaceBreak"] = function(parser) + local start = parser.pos + -- Position-pure rule: a single-slot memo short-circuits the repeated + -- calls that backtracking alternatives make at the same position + if parser.memo_pos[8] == start + 1 then + local memo_end = parser.memo_end[8] + if memo_end == -1 then + parser.success = false + return false + end + parser.pos = memo_end + parser.success = true + return true + end +local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- sequence with 2 patterns + local pp_pos = parser.pos + rules["Space"](parser) +if parser.success then +rules["Break"](parser) +end + if not parser.success then + parser.pos = pp_pos + end +end + parser.memo_pos[8] = start + 1 + parser.memo_end[8] = parser.success and parser.pos or -1 + + parser.depth = depth - 1 + return parser.success +end + + +rules["Statement"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- transform capture (Cfn id=1) + local fn_cap_start = parser.cap_n + cap_push(parser, CAP_FN_OPEN, cmt_fns[1], parser.pos, 0) + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- transform capture (Cfn id=2) + local fn_cap_start = parser.cap_n + cap_push(parser, CAP_FN_OPEN, cmt_fns[2], parser.pos, 0) + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + cap_push(parser, CAP_POS, nil, parser.pos, 0) -- position capture +if parser.success then +do -- FIRST-byte dispatched ordered choice + local dd = disp[7] + local db = byte(parser.input, parser.pos + 1) + local dm = db and dd.bytes[db] or dd.eof + parser.success = false + if not parser.success and not parser.throw_label and dm[1] then + parser.success = true + rules["Import"](parser) +end +if not parser.success and not parser.throw_label and dm[2] then + if dm.s[2] then record_furthest(parser) end + parser.success = true + rules["While"](parser) +end +if not parser.success and not parser.throw_label and dm[3] then + if dm.s[3] then record_furthest(parser) end + parser.success = true + rules["With"](parser) +end +if not parser.success and not parser.throw_label and dm[4] then + if dm.s[4] then record_furthest(parser) end + parser.success = true + rules["For"](parser) +end +if not parser.success and not parser.throw_label and dm[5] then + if dm.s[5] then record_furthest(parser) end + parser.success = true + rules["ForEach"](parser) +end +if not parser.success and not parser.throw_label and dm[6] then + if dm.s[6] then record_furthest(parser) end + parser.success = true + rules["Switch"](parser) +end +if not parser.success and not parser.throw_label and dm[7] then + if dm.s[7] then record_furthest(parser) end + parser.success = true + rules["Return"](parser) +end +if not parser.success and not parser.throw_label and dm[8] then + if dm.s[8] then record_furthest(parser) end + parser.success = true + rules["Local"](parser) +end +if not parser.success and not parser.throw_label and dm[9] then + if dm.s[9] then record_furthest(parser) end + parser.success = true + rules["Export"](parser) +end +if not parser.success and not parser.throw_label and dm[10] then + if dm.s[10] then record_furthest(parser) end + parser.success = true + rules["BreakLoop"](parser) +end +if not parser.success and not parser.throw_label and dm[11] then + if dm.s[11] then record_furthest(parser) end + parser.success = true + do -- transform capture (Cfn id=3) + local fn_cap_start = parser.cap_n + cap_push(parser, CAP_FN_OPEN, cmt_fns[3], parser.pos, 0) + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + rules["ExpList"](parser) + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + do -- choice with 2 alternatives + rules["Update"](parser) +if not parser.success and not parser.throw_label then + parser.success = true + rules["Assign"](parser) +end +end + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_FN_CLOSE, nil, parser.pos, 0) + else + parser.cap_n = fn_cap_start + end +end +end + if not parser.success and not parser.throw_label then + record_furthest(parser) + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_FN_CLOSE, nil, parser.pos, 0) + else + parser.cap_n = fn_cap_start + end +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- choice with 3 alternatives + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 7 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "if", 0, 0) +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match literal "if" +if sub(parser.input, parser.pos + 1, parser.pos + 2) == "if" then + parser.pos = parser.pos + 2 +else + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character range "az,AZ,09,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 48 and rb <= 57) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end +if parser.success then +rules["Exp"](parser) +end +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + do -- sequence with 4 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +-- match literal "else" +if sub(parser.input, parser.pos + 1, parser.pos + 4) == "else" then + parser.pos = parser.pos + 4 +else + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character range "az,AZ,09,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 48 and rb <= 57) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end +if parser.success then +rules["Exp"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end +if parser.success then +rules["Space"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +if not parser.success and not parser.throw_label then + parser.success = true + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 5 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "unless", 0, 0) +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match literal "unless" +if sub(parser.input, parser.pos + 1, parser.pos + 6) == "unless" then + parser.pos = parser.pos + 6 +else + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character range "az,AZ,09,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 48 and rb <= 57) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end +if parser.success then +rules["Exp"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end +if not parser.success and not parser.throw_label then + parser.success = true + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "comprehension", 0, 0) +end +if parser.success then +rules["CompInner"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end +end +if parser.success then +rules["Space"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_FN_CLOSE, nil, parser.pos, 0) + else + parser.cap_n = fn_cap_start + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["Stop"] = function(parser) + local start = parser.pos + -- Position-pure rule: a single-slot memo short-circuits the repeated + -- calls that backtracking alternatives make at the same position + if parser.memo_pos[9] == start + 1 then + local memo_end = parser.memo_end[9] + if memo_end == -1 then + parser.success = false + return false + end + parser.pos = memo_end + parser.success = true + return true + end +local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- choice with 2 alternatives + rules["Break"](parser) +if not parser.success and not parser.throw_label then + parser.success = true + do -- negate (only match if pattern fails) + local pp_pos = parser.pos + -- match any 1 characters +if parser.pos + 1 <= parser.input_len then + parser.pos = parser.pos + 1 +else + parser.success = false + record_furthest(parser) + +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end +end + parser.memo_pos[9] = start + 1 + parser.memo_end[9] = parser.success and parser.pos or -1 + + parser.depth = depth - 1 + return parser.success +end + + +rules["String"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- choice with 3 alternatives + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +rules["DoubleString"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +if not parser.success and not parser.throw_label then + parser.success = true + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +rules["SingleString"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +end +if not parser.success and not parser.throw_label then + parser.success = true + rules["LuaString"](parser) +end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["Switch"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 11 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "switch", 0, 0) +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match literal "switch" +if sub(parser.input, parser.pos + 1, parser.pos + 6) == "switch" then + parser.pos = parser.pos + 6 +else + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character range "az,AZ,09,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 48 and rb <= 57) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end +if parser.success then +-- indenter cpush (stack 1): push constant 0 +ind_push(parser, 2, 0) +end +if parser.success then +rules["Exp"](parser) +end +if parser.success then +-- indenter pop (stack 1) +if not ind_pop(parser, 2) then + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + do -- sequence with 3 patterns + local pp_pos = parser.pos + rules["Space"](parser) +if parser.success then +-- match literal "do" +if sub(parser.input, parser.pos + 1, parser.pos + 2) == "do" then + parser.pos = parser.pos + 2 +else + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character range "az,AZ,09,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 48 and rb <= 57) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end + if not parser.success then + parser.pos = pp_pos + end +end + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +rules["Break"](parser) +end +if parser.success then +rules["SwitchBlock"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["SwitchBlock"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- sequence with 4 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- zero or more repetitions + while true do + rules["EmptyLine"](parser) + if not parser.success then + break + end + end + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end +end +if parser.success then +rules["Advance"](parser) +end +if parser.success then +do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["SwitchCase"](parser) +if parser.success then +do -- zero or more repetitions + while true do + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- at least 1 repetitions + local pp_pos = parser.pos + local rep_count = 0 + while true do + rules["Break"](parser) + if not parser.success then + break + end + rep_count = rep_count + 1 + end + if parser.throw_label then + -- Keep failure state, propagate labeled failure + elseif rep_count >= 1 then + parser.success = true + else + parser.pos = pp_pos + + end +end +if parser.success then +rules["SwitchCase"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if not parser.success then + break + end + end + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end +end +end +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- at least 1 repetitions + local pp_pos = parser.pos + local rep_count = 0 + while true do + rules["Break"](parser) + if not parser.success then + break + end + rep_count = rep_count + 1 + end + if parser.throw_label then + -- Keep failure state, propagate labeled failure + elseif rep_count >= 1 then + parser.success = true + else + parser.pos = pp_pos + + end +end +if parser.success then +rules["SwitchElse"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end +if parser.success then +rules["PopIndent"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["SwitchCase"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 7 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "case", 0, 0) +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match literal "when" +if sub(parser.input, parser.pos + 1, parser.pos + 4) == "when" then + parser.pos = parser.pos + 4 +else + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character range "az,AZ,09,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 48 and rb <= 57) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end +if parser.success then +do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + rules["ExpList"](parser) + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + do -- sequence with 3 patterns + local pp_pos = parser.pos + rules["Space"](parser) +if parser.success then +-- match literal "then" +if sub(parser.input, parser.pos + 1, parser.pos + 4) == "then" then + parser.pos = parser.pos + 4 +else + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character range "az,AZ,09,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 48 and rb <= 57) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end + if not parser.success then + parser.pos = pp_pos + end +end + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end +if parser.success then +rules["Body"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["SwitchElse"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 5 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "else", 0, 0) +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match literal "else" +if sub(parser.input, parser.pos + 1, parser.pos + 4) == "else" then + parser.pos = parser.pos + 4 +else + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character range "az,AZ,09,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 48 and rb <= 57) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end +if parser.success then +rules["Body"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["TableBlock"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 5 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "table", 0, 0) +end +if parser.success then +do -- at least 1 repetitions + local pp_pos = parser.pos + local rep_count = 0 + while true do + rules["SpaceBreak"](parser) + if not parser.success then + break + end + rep_count = rep_count + 1 + end + if parser.throw_label then + -- Keep failure state, propagate labeled failure + elseif rep_count >= 1 then + parser.success = true + else + parser.pos = pp_pos + + end +end +end +if parser.success then +rules["Advance"](parser) +end +if parser.success then +rules["TableBlockInner"](parser) +end +if parser.success then +rules["PopIndent"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["TableBlockInner"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["KeyValueLine"](parser) +if parser.success then +do -- zero or more repetitions + while true do + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- at least 1 repetitions + local pp_pos = parser.pos + local rep_count = 0 + while true do + rules["SpaceBreak"](parser) + if not parser.success then + break + end + rep_count = rep_count + 1 + end + if parser.throw_label then + -- Keep failure state, propagate labeled failure + elseif rep_count >= 1 then + parser.success = true + else + parser.pos = pp_pos + + end +end +if parser.success then +rules["KeyValueLine"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if not parser.success then + break + end + end + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["TableLit"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 7 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "table", 0, 0) +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match single character "{" +if byte(parser.input, parser.pos + 1) == 123 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end +if parser.success then +do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + rules["TableValueList"](parser) + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + do -- sequence with 2 patterns + local pp_pos = parser.pos + rules["Space"](parser) +if parser.success then +-- match single character "," +if byte(parser.input, parser.pos + 1) == 44 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end + if not parser.success then + parser.pos = pp_pos + end +end + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + do -- sequence with 4 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["SpaceBreak"](parser) +if parser.success then +rules["TableLitLine"](parser) +end +if parser.success then +do -- zero or more repetitions + while true do + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + do -- sequence with 2 patterns + local pp_pos = parser.pos + rules["Space"](parser) +if parser.success then +-- match single character "," +if byte(parser.input, parser.pos + 1) == 44 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end + if not parser.success then + parser.pos = pp_pos + end +end + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +if parser.success then +rules["SpaceBreak"](parser) +end +if parser.success then +rules["TableLitLine"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if not parser.success then + break + end + end + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end +end +end +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + do -- sequence with 2 patterns + local pp_pos = parser.pos + rules["Space"](parser) +if parser.success then +-- match single character "," +if byte(parser.input, parser.pos + 1) == 44 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end + if not parser.success then + parser.pos = pp_pos + end +end + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end +if parser.success then +rules["White"](parser) +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match single character "}" +if byte(parser.input, parser.pos + 1) == 125 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["TableLitLine"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- choice with 2 alternatives + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["PushIndent"](parser) +if parser.success then +rules["TableValueList"](parser) +end +if parser.success then +rules["PopIndent"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +if not parser.success and not parser.throw_label then + parser.success = true + rules["Space"](parser) +end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["TableValue"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- choice with 2 alternatives + rules["KeyValue"](parser) +if not parser.success and not parser.throw_label then + parser.success = true + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + rules["Exp"](parser) + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["TableValueList"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["TableValue"](parser) +if parser.success then +do -- zero or more repetitions + while true do + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +-- match single character "," +if byte(parser.input, parser.pos + 1) == 44 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end +if parser.success then +rules["TableValue"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if not parser.success then + break + end + end + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["TblComprehension"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 7 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "tblcomprehension", 0, 0) +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match single character "{" +if byte(parser.input, parser.pos + 1) == 123 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end +if parser.success then +do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Exp"](parser) +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +-- match single character "," +if byte(parser.input, parser.pos + 1) == 44 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end +if parser.success then +rules["Exp"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end +if parser.success then +rules["CompInner"](parser) +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match single character "}" +if byte(parser.input, parser.pos + 1) == 125 then + parser.pos = parser.pos + 1 +else + parser.success = false + +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["Unless"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 9 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "unless", 0, 0) +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match literal "unless" +if sub(parser.input, parser.pos + 1, parser.pos + 6) == "unless" then + parser.pos = parser.pos + 6 +else + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character range "az,AZ,09,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 48 and rb <= 57) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end +if parser.success then +rules["IfCond"](parser) +end +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + do -- sequence with 3 patterns + local pp_pos = parser.pos + rules["Space"](parser) +if parser.success then +-- match literal "then" +if sub(parser.input, parser.pos + 1, parser.pos + 4) == "then" then + parser.pos = parser.pos + 4 +else + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character range "az,AZ,09,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 48 and rb <= 57) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end + if not parser.success then + parser.pos = pp_pos + end +end + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end +if parser.success then +rules["Body"](parser) +end +if parser.success then +do -- zero or more repetitions + while true do + rules["IfElseIf"](parser) + if not parser.success then + break + end + end + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end +end +end +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + rules["IfElse"](parser) + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["Update"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 4 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "update", 0, 0) +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +do -- capture + local cap_start_pos = parser.pos + do -- trie match for: "..=", "+=", "-=", "*=", "/=", "%=", "or=", "and=", "&=", "|=", ">>=", "<<=" + local trie_pos = parser.pos + local last_terminal_pos = 0 + local has_terminal = false + local tb = byte(parser.input, parser.pos + 1) +if tb == 37 then -- "%" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 61 then -- "=" + parser.pos = parser.pos + 1 +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +elseif tb == 38 then -- "&" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 61 then -- "=" + parser.pos = parser.pos + 1 +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +elseif tb == 42 then -- "*" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 61 then -- "=" + parser.pos = parser.pos + 1 +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +elseif tb == 43 then -- "+" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 61 then -- "=" + parser.pos = parser.pos + 1 +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +elseif tb == 45 then -- "-" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 61 then -- "=" + parser.pos = parser.pos + 1 +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +elseif tb == 46 then -- "." + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 46 then -- "." + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 61 then -- "=" + parser.pos = parser.pos + 1 +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +elseif tb == 47 then -- "/" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 61 then -- "=" + parser.pos = parser.pos + 1 +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +elseif tb == 60 then -- "<" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 60 then -- "<" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 61 then -- "=" + parser.pos = parser.pos + 1 +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +elseif tb == 62 then -- ">" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 62 then -- ">" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 61 then -- "=" + parser.pos = parser.pos + 1 +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +elseif tb == 97 then -- "a" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 110 then -- "n" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 100 then -- "d" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 61 then -- "=" + parser.pos = parser.pos + 1 +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +elseif tb == 111 then -- "o" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 114 then -- "r" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 61 then -- "=" + parser.pos = parser.pos + 1 +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +elseif tb == 124 then -- "|" + parser.pos = parser.pos + 1 +local tb = byte(parser.input, parser.pos + 1) +if tb == 61 then -- "=" + parser.pos = parser.pos + 1 +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end +else + parser.success = false + if has_terminal then + parser.pos = last_terminal_pos + parser.success = true + else + record_furthest(parser) + end +end + if not parser.success then + parser.pos = trie_pos + end +end + if parser.success then + cap_push(parser, CAP_STR, nil, cap_start_pos, parser.pos - cap_start_pos) + end +end +end +if parser.success then +rules["Exp"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["Value"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- transform capture (Cfn id=2) + local fn_cap_start = parser.cap_n + cap_push(parser, CAP_FN_OPEN, cmt_fns[2], parser.pos, 0) + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + cap_push(parser, CAP_POS, nil, parser.pos, 0) -- position capture +if parser.success then +do -- FIRST-byte dispatched ordered choice + local dd = disp[8] + local db = byte(parser.input, parser.pos + 1) + local dm = db and dd.bytes[db] or dd.eof + parser.success = false + if not parser.success and not parser.throw_label and dm[1] then + parser.success = true + rules["SimpleValue"](parser) +end +if not parser.success and not parser.throw_label and dm[2] then + if dm.s[2] then record_furthest(parser) end + parser.success = true + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "table", 0, 0) +end +if parser.success then +do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + rules["KeyValueList"](parser) + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +end +if not parser.success and not parser.throw_label and dm[3] then + if dm.s[3] then record_furthest(parser) end + parser.success = true + rules["ChainValue"](parser) +end +if not parser.success and not parser.throw_label and dm[4] then + if dm.s[4] then record_furthest(parser) end + parser.success = true + rules["String"](parser) +end + if not parser.success and not parser.throw_label then + record_furthest(parser) + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_FN_CLOSE, nil, parser.pos, 0) + else + parser.cap_n = fn_cap_start + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["VarArg"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +do -- capture + local cap_start_pos = parser.pos + -- match literal "..." +if sub(parser.input, parser.pos + 1, parser.pos + 3) == "..." then + parser.pos = parser.pos + 3 +else + parser.success = false + record_furthest(parser) + +end + if parser.success then + cap_push(parser, CAP_STR, nil, cap_start_pos, parser.pos - cap_start_pos) + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["While"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 9 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "while", 0, 0) +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match literal "while" +if sub(parser.input, parser.pos + 1, parser.pos + 5) == "while" then + parser.pos = parser.pos + 5 +else + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character range "az,AZ,09,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 48 and rb <= 57) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end +if parser.success then +-- indenter cpush (stack 1): push constant 0 +ind_push(parser, 2, 0) +end +if parser.success then +rules["Exp"](parser) +end +if parser.success then +-- indenter pop (stack 1) +if not ind_pop(parser, 2) then + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + do -- sequence with 3 patterns + local pp_pos = parser.pos + rules["Space"](parser) +if parser.success then +-- match literal "do" +if sub(parser.input, parser.pos + 1, parser.pos + 2) == "do" then + parser.pos = parser.pos + 2 +else + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character range "az,AZ,09,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 48 and rb <= 57) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end + if not parser.success then + parser.pos = pp_pos + end +end + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end +if parser.success then +rules["Body"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["White"] = function(parser) + local start = parser.pos + -- Position-pure rule: a single-slot memo short-circuits the repeated + -- calls that backtracking alternatives make at the same position + if parser.memo_pos[10] == start + 1 then + local memo_end = parser.memo_end[10] + if memo_end == -1 then + parser.success = false + return false + end + parser.pos = memo_end + parser.success = true + return true + end +local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- zero or more repetitions + while true do + do -- match character set " \t\r\n" + local sb = byte(parser.input, parser.pos + 1) + if sb and sets[8][sb] then + parser.pos = parser.pos + 1 + else + parser.success = false + end +end + if not parser.success then + break + end + end + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end +end + parser.memo_pos[10] = start + 1 + parser.memo_end[10] = parser.success and parser.pos or -1 + + parser.depth = depth - 1 + return parser.success +end + + +rules["With"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + do -- sequence with 9 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- constant capture (1 values) + cap_push(parser, CAP_CONST, "with", 0, 0) +end +if parser.success then +rules["Space"](parser) +end +if parser.success then +-- match literal "with" +if sub(parser.input, parser.pos + 1, parser.pos + 4) == "with" then + parser.pos = parser.pos + 4 +else + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character range "az,AZ,09,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 48 and rb <= 57) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end +if parser.success then +-- indenter cpush (stack 1): push constant 0 +ind_push(parser, 2, 0) +end +if parser.success then +rules["WithExp"](parser) +end +if parser.success then +-- indenter pop (stack 1) +if not ind_pop(parser, 2) then + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + do -- sequence with 3 patterns + local pp_pos = parser.pos + rules["Space"](parser) +if parser.success then +-- match literal "do" +if sub(parser.input, parser.pos + 1, parser.pos + 2) == "do" then + parser.pos = parser.pos + 2 +else + parser.success = false + record_furthest(parser) + +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character range "az,AZ,09,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 48 and rb <= 57) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end + if not parser.success then + parser.pos = pp_pos + end +end + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end +if parser.success then +rules["Body"](parser) +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["WithExp"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- transform capture (Cfn id=3) + local fn_cap_start = parser.cap_n + cap_push(parser, CAP_FN_OPEN, cmt_fns[3], parser.pos, 0) + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + do -- capture table + local ct_cap_start = parser.cap_n + cap_push(parser, CAP_TBL_OPEN, nil, 0, 0) + rules["ExpList"](parser) + if parser.success then + cap_push(parser, CAP_TBL_CLOSE, nil, 0, 0) + else + parser.cap_n = ct_cap_start + end +end +if parser.success then +do -- at most 1 repetitions + local rep_count = 0 + while rep_count < 1 do + local before_pos = parser.pos + rules["Assign"](parser) + if not parser.success or before_pos == parser.pos then + -- Break on failure or zero-width match + -- Only recover from ordinary failure, not labeled failure from T() + if not parser.throw_label then + parser.success = true + end + break + end + rep_count = rep_count + 1 + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end + if parser.success then + cap_push(parser, CAP_FN_CLOSE, nil, parser.pos, 0) + else + parser.cap_n = fn_cap_start + end +end + + parser.depth = depth - 1 + return parser.success +end + + +rules["WordOperators"] = function(parser) + local depth = parser.depth + 1 + parser.depth = depth + if depth > MAX_DEPTH then + -- A hard Lua error (rather than a match failure) so the overflow can't + -- be silently converted into a successful parse by a predicate or choice + error("pgen: max recursion depth (" .. MAX_DEPTH .. ") exceeded at position " .. (parser.pos + 1)) + end + + do -- FIRST-byte dispatched ordered choice + local dd = disp[9] + local db = byte(parser.input, parser.pos + 1) + local dm = db and dd.bytes[db] or dd.eof + parser.success = false + if not parser.success and not parser.throw_label and dm[1] then + parser.success = true + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +do -- capture + local cap_start_pos = parser.pos + -- match literal "or" +if sub(parser.input, parser.pos + 1, parser.pos + 2) == "or" then + parser.pos = parser.pos + 2 +else + parser.success = false + record_furthest(parser) + +end + if parser.success then + cap_push(parser, CAP_STR, nil, cap_start_pos, parser.pos - cap_start_pos) + end +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character range "az,AZ,09,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 48 and rb <= 57) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +end +if not parser.success and not parser.throw_label and dm[2] then + if dm.s[2] then record_furthest(parser) end + parser.success = true + do -- sequence with 3 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +do -- capture + local cap_start_pos = parser.pos + -- match literal "and" +if sub(parser.input, parser.pos + 1, parser.pos + 3) == "and" then + parser.pos = parser.pos + 3 +else + parser.success = false + record_furthest(parser) + +end + if parser.success then + cap_push(parser, CAP_STR, nil, cap_start_pos, parser.pos - cap_start_pos) + end +end +end +if parser.success then +do -- negate (only match if pattern fails) + local pp_pos = parser.pos + do -- match character range "az,AZ,09,__" + local rb = byte(parser.input, parser.pos + 1) + if rb and ((rb >= 97 and rb <= 122) or (rb >= 65 and rb <= 90) or (rb >= 48 and rb <= 57) or (rb >= 95 and rb <= 95)) then + parser.pos = parser.pos + 1 + else + parser.success = false + + end +end + if parser.success then + -- Pattern matched, so negate fails + parser.pos = pp_pos + parser.success = false + record_furthest(parser) + + else + -- Pattern failed, so negate succeeds + parser.success = true + -- Swallow labeled failures inside predicates (LPegLabel behavior) + if parser.throw_label then + parser.throw_label = nil + parser.throw_pos = 0 + end + parser.pos = pp_pos + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +end +if not parser.success and not parser.throw_label and dm[3] then + if dm.s[3] then record_furthest(parser) end + parser.success = true + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +do -- capture + local cap_start_pos = parser.pos + -- match literal "<=" +if sub(parser.input, parser.pos + 1, parser.pos + 2) == "<=" then + parser.pos = parser.pos + 2 +else + parser.success = false + record_furthest(parser) + +end + if parser.success then + cap_push(parser, CAP_STR, nil, cap_start_pos, parser.pos - cap_start_pos) + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +end +if not parser.success and not parser.throw_label and dm[4] then + if dm.s[4] then record_furthest(parser) end + parser.success = true + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +do -- capture + local cap_start_pos = parser.pos + -- match literal ">=" +if sub(parser.input, parser.pos + 1, parser.pos + 2) == ">=" then + parser.pos = parser.pos + 2 +else + parser.success = false + record_furthest(parser) + +end + if parser.success then + cap_push(parser, CAP_STR, nil, cap_start_pos, parser.pos - cap_start_pos) + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +end +if not parser.success and not parser.throw_label and dm[5] then + if dm.s[5] then record_furthest(parser) end + parser.success = true + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +do -- capture + local cap_start_pos = parser.pos + -- match literal "~=" +if sub(parser.input, parser.pos + 1, parser.pos + 2) == "~=" then + parser.pos = parser.pos + 2 +else + parser.success = false + record_furthest(parser) + +end + if parser.success then + cap_push(parser, CAP_STR, nil, cap_start_pos, parser.pos - cap_start_pos) + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +end +if not parser.success and not parser.throw_label and dm[6] then + if dm.s[6] then record_furthest(parser) end + parser.success = true + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +do -- capture + local cap_start_pos = parser.pos + -- match literal "!=" +if sub(parser.input, parser.pos + 1, parser.pos + 2) == "!=" then + parser.pos = parser.pos + 2 +else + parser.success = false + record_furthest(parser) + +end + if parser.success then + cap_push(parser, CAP_STR, nil, cap_start_pos, parser.pos - cap_start_pos) + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +end +if not parser.success and not parser.throw_label and dm[7] then + if dm.s[7] then record_furthest(parser) end + parser.success = true + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +do -- capture + local cap_start_pos = parser.pos + -- match literal "==" +if sub(parser.input, parser.pos + 1, parser.pos + 2) == "==" then + parser.pos = parser.pos + 2 +else + parser.success = false + record_furthest(parser) + +end + if parser.success then + cap_push(parser, CAP_STR, nil, cap_start_pos, parser.pos - cap_start_pos) + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +end +if not parser.success and not parser.throw_label and dm[8] then + if dm.s[8] then record_furthest(parser) end + parser.success = true + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +do -- capture + local cap_start_pos = parser.pos + -- match literal ".." +if sub(parser.input, parser.pos + 1, parser.pos + 2) == ".." then + parser.pos = parser.pos + 2 +else + parser.success = false + record_furthest(parser) + +end + if parser.success then + cap_push(parser, CAP_STR, nil, cap_start_pos, parser.pos - cap_start_pos) + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +end +if not parser.success and not parser.throw_label and dm[9] then + if dm.s[9] then record_furthest(parser) end + parser.success = true + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +do -- capture + local cap_start_pos = parser.pos + -- match literal "<<" +if sub(parser.input, parser.pos + 1, parser.pos + 2) == "<<" then + parser.pos = parser.pos + 2 +else + parser.success = false + record_furthest(parser) + +end + if parser.success then + cap_push(parser, CAP_STR, nil, cap_start_pos, parser.pos - cap_start_pos) + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +end +if not parser.success and not parser.throw_label and dm[10] then + if dm.s[10] then record_furthest(parser) end + parser.success = true + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +do -- capture + local cap_start_pos = parser.pos + -- match literal ">>" +if sub(parser.input, parser.pos + 1, parser.pos + 2) == ">>" then + parser.pos = parser.pos + 2 +else + parser.success = false + record_furthest(parser) + +end + if parser.success then + cap_push(parser, CAP_STR, nil, cap_start_pos, parser.pos - cap_start_pos) + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +end +if not parser.success and not parser.throw_label and dm[11] then + if dm.s[11] then record_furthest(parser) end + parser.success = true + do -- sequence with 2 patterns + local pp_pos, pp_cap, pp_trail = parser.pos, parser.cap_n, parser.trail_n + rules["Space"](parser) +if parser.success then +do -- capture + local cap_start_pos = parser.pos + -- match literal "//" +if sub(parser.input, parser.pos + 1, parser.pos + 2) == "//" then + parser.pos = parser.pos + 2 +else + parser.success = false + record_furthest(parser) + +end + if parser.success then + cap_push(parser, CAP_STR, nil, cap_start_pos, parser.pos - cap_start_pos) + end +end +end + if not parser.success then + parser.pos = pp_pos parser.cap_n = pp_cap ind_trail_rewind(parser, pp_trail) + end +end +end + if not parser.success and not parser.throw_label then + record_furthest(parser) + end +end + + parser.depth = depth - 1 + return parser.success +end + + +local function new_parser(input) + return { + input = input, + input_len = #input, + pos = 0, -- 0-based like the C target; converted at the API boundary + success = true, + throw_label = nil, -- label from T() or nil for ordinary failure + throw_pos = 0, + furthest_fail = 0, + depth = 0, + cap_kind = {}, cap_aux = {}, cap_start = {}, cap_size = {}, + cap_n = 0, + values = {}, values_n = 0, + memo_pos = {}, memo_end = {}, + ind_stacks = { { 0, n = 1 }, { 1, n = 1 } }, + trail_id = {}, trail_op = {}, trail_val = {}, trail_n = 0, + } +end + +local function parse(input) + if type(input) == "number" then + input = tostring(input) + end + if type(input) ~= "string" then + error("Expected string argument for parsing") + end + + local parser = new_parser(input) + + rules["Root"](parser) + + -- Return nil and error info on failure + if not parser.success then + if parser.throw_label then + -- Labeled failure: return nil, label, position + return nil, parser.throw_label, parser.throw_pos + 1 + end + -- Ordinary failure: return nil, message (pgen_errors builds only) and + -- the furthest input position a match attempt failed at (1-indexed) + return nil, nil, parser.furthest_fail + 1 + end + + -- Materialize the capture log into return values. Named groups produce + -- no top-level values (they only matter inside Ct). + local out = {n = 0} + local i = 1 + local ck = parser.cap_kind + while i <= parser.cap_n do + if ck[i] == CAP_GROUP_OPEN then + i = cap_skip(parser, i) + else + i = cap_eval(parser, i, out) + end + end + + if out.n > 0 then + -- Probe large result lists first: unpack past the runtime's stack limit + -- must surface as a clean, recognizable error + if out.n >= 1000 and not pcall(unpack, out, 1, out.n) then + error("pgen: Lua stack overflow while building captures") + end + return unpack(out, 1, out.n) + end + + -- Success case with no captures: return position of consumed input + return parser.pos + 1 +end + +return { + parse = parse +} diff --git a/moonscript/parse/tree.lua b/moonscript/parse/tree.lua new file mode 100644 index 00000000..8527dabd --- /dev/null +++ b/moonscript/parse/tree.lua @@ -0,0 +1,105 @@ +local unpack = unpack or table.unpack +local ntype +ntype = function(node) + if type(node) == "table" then + return node[1] + end + return "value" +end +local chain_assignable = { + index = true, + dot = true, + slice = true +} +local is_assignable +is_assignable = function(node) + if node == "..." then + return false + end + local _exp_0 = ntype(node) + if "ref" == _exp_0 or "self" == _exp_0 or "value" == _exp_0 or "self_class" == _exp_0 or "table" == _exp_0 then + return true + elseif "chain" == _exp_0 then + return chain_assignable[ntype(node[#node])] + else + return false + end +end +local flatten_or_mark +flatten_or_mark = function(name) + return function(tbl) + if #tbl == 1 then + return tbl[1] + end + table.insert(tbl, 1, name) + return tbl + end +end +local flatten_explist = flatten_or_mark("explist") +local format_assign +format_assign = function(lhs_exps, assign) + if not (assign) then + return flatten_explist(lhs_exps) + end + for _index_0 = 1, #lhs_exps do + local assign_exp = lhs_exps[_index_0] + if not (is_assignable(assign_exp)) then + error({ + assign_exp, + "left hand expression is not assignable" + }) + end + end + local t = ntype(assign) + local _exp_0 = t + if "assign" == _exp_0 then + return { + "assign", + lhs_exps, + unpack(assign, 2) + } + elseif "update" == _exp_0 then + return { + "update", + lhs_exps[1], + unpack(assign, 2) + } + else + return error("unknown assign expression: " .. tostring(t)) + end +end +local format_single_assign +format_single_assign = function(lhs, assign) + if assign then + return format_assign({ + lhs + }, assign) + end + return lhs +end +local join_chain +join_chain = function(callee, args) + if #args == 0 then + return callee + end + args = { + "call", + args + } + if ntype(callee) == "chain" then + table.insert(callee, args) + return callee + end + return { + "chain", + callee, + args + } +end +return { + ntype = ntype, + is_assignable = is_assignable, + format_assign = format_assign, + format_single_assign = format_single_assign, + join_chain = join_chain +} diff --git a/moonscript/parse/tree.moon b/moonscript/parse/tree.moon new file mode 100644 index 00000000..170e8360 --- /dev/null +++ b/moonscript/parse/tree.moon @@ -0,0 +1,71 @@ +-- Transform helpers for the grammar's Cfn callbacks. The callbacks +-- themselves live as code strings in grammar.moon and require this module +-- at parser load. +-- +-- format_assign raises error({node, msg}) for invalid assignment targets; +-- it propagates out of parse() and is formatted by moonscript/parse.moon. + +unpack = unpack or table.unpack + +-- never called with nil: that would report "value" +ntype = (node) -> + if type(node) == "table" + return node[1] + + "value" + +chain_assignable = {index: true, dot: true, slice: true} + +is_assignable = (node) -> + return false if node == "..." + + switch ntype node + when "ref", "self", "value", "self_class", "table" + true + when "chain" + chain_assignable[ntype node[#node]] + else + false + +flatten_or_mark = (name) -> + (tbl) -> + return tbl[1] if #tbl == 1 + table.insert tbl, 1, name + tbl + +flatten_explist = flatten_or_mark "explist" + +format_assign = (lhs_exps, assign) -> + unless assign + return flatten_explist lhs_exps + + for assign_exp in *lhs_exps + unless is_assignable assign_exp + error {assign_exp, "left hand expression is not assignable"} + + t = ntype assign + switch t + when "assign" + {"assign", lhs_exps, unpack assign, 2} + when "update" + {"update", lhs_exps[1], unpack assign, 2} + else + error "unknown assign expression: #{t}" + +format_single_assign = (lhs, assign) -> + if assign + return format_assign {lhs}, assign + + lhs + +join_chain = (callee, args) -> + return callee if #args == 0 + args = {"call", args} + + if ntype(callee) == "chain" + table.insert callee, args + return callee + + {"chain", callee, args} + +{ :ntype, :is_assignable, :format_assign, :format_single_assign, :join_chain } diff --git a/moonscript/parse/util.lua b/moonscript/parse/util.lua deleted file mode 100644 index 8f29241b..00000000 --- a/moonscript/parse/util.lua +++ /dev/null @@ -1,289 +0,0 @@ -local unpack -unpack = require("moonscript.util").unpack -local P, C, S, Cp, Cmt, V -do - local _obj_0 = require("lpeg") - P, C, S, Cp, Cmt, V = _obj_0.P, _obj_0.C, _obj_0.S, _obj_0.Cp, _obj_0.Cmt, _obj_0.V -end -local ntype, is_assignable -do - local _obj_0 = require("moonscript.types") - ntype, is_assignable = _obj_0.ntype, _obj_0.is_assignable -end -local Space -Space = require("moonscript.parse.literals").Space -local Indent = C(S("\t ") ^ 0) / function(str) - do - local sum = 0 - for v in str:gmatch("[\t ]") do - local _exp_0 = v - if " " == _exp_0 then - sum = sum + 1 - elseif "\t" == _exp_0 then - sum = sum + 4 - end - end - return sum - end -end -local Cut = P(function() - return false -end) -local ensure -ensure = function(patt, finally) - return patt * finally + finally * Cut -end -local extract_line -extract_line = function(str, start_pos) - str = str:sub(start_pos) - do - local m = str:match("^(.-)\n") - if m then - return m - end - end - return str:match("^.-$") -end -local show_line_position -show_line_position = function(str, pos, context) - if context == nil then - context = true - end - local lines = { - { } - } - for c in str:gmatch(".") do - local _update_0 = #lines - lines[_update_0] = lines[_update_0] or { } - table.insert(lines[#lines], c) - if c == "\n" then - lines[#lines + 1] = { } - end - end - for i, line in ipairs(lines) do - lines[i] = table.concat(line) - end - local out - local remaining = pos - 1 - for k, line in ipairs(lines) do - if remaining < #line then - local left = line:sub(1, remaining) - local right = line:sub(remaining + 1) - out = { - tostring(left) .. "◉" .. tostring(right) - } - if context then - do - local before = lines[k - 1] - if before then - table.insert(out, 1, before) - end - end - do - local after = lines[k + 1] - if after then - table.insert(out, after) - end - end - end - break - else - remaining = remaining - #line - end - end - if not (out) then - return "-" - end - out = table.concat(out) - return (out:gsub("\n*$", "")) -end -local mark -mark = function(name) - return function(...) - return { - name, - ... - } - end -end -local pos -pos = function(patt) - return (Cp() * patt) / function(pos, value) - if type(value) == "table" then - value[-1] = pos - end - return value - end -end -local got -got = function(what, context) - if context == nil then - context = true - end - return Cmt("", function(str, pos) - print("++ got " .. tostring(what), "[" .. tostring(show_line_position(str, pos, context)) .. "]") - return true - end) -end -local flatten_or_mark -flatten_or_mark = function(name) - return function(tbl) - if #tbl == 1 then - return tbl[1] - end - table.insert(tbl, 1, name) - return tbl - end -end -local check_assignable -check_assignable = function(str, pos, value) - if is_assignable(value) then - return true, value - else - return false - end -end -local format_assign -do - local flatten_explist = flatten_or_mark("explist") - format_assign = function(lhs_exps, assign) - if not (assign) then - return flatten_explist(lhs_exps) - end - for _index_0 = 1, #lhs_exps do - local assign_exp = lhs_exps[_index_0] - if not (is_assignable(assign_exp)) then - error({ - assign_exp, - "left hand expression is not assignable" - }) - end - end - local t = ntype(assign) - local _exp_0 = t - if "assign" == _exp_0 then - return { - "assign", - lhs_exps, - unpack(assign, 2) - } - elseif "update" == _exp_0 then - return { - "update", - lhs_exps[1], - unpack(assign, 2) - } - else - return error("unknown assign expression: " .. tostring(t)) - end - end -end -local format_single_assign -format_single_assign = function(lhs, assign) - if assign then - return format_assign({ - lhs - }, assign) - else - return lhs - end -end -local sym -sym = function(chars) - return Space * chars -end -local symx -symx = function(chars) - return chars -end -local simple_string -simple_string = function(delim, allow_interpolation) - local inner = P("\\" .. tostring(delim)) + "\\\\" + (1 - P(delim)) - if allow_interpolation then - local interp = symx('#{') * V("Exp") * sym('}') - inner = (C((inner - symx('#{')) ^ 1) + interp / mark("interpolate")) ^ 0 - else - inner = C(inner ^ 0) - end - return C(symx(delim)) * inner * sym(delim) / mark("string") -end -local wrap_func_arg -wrap_func_arg = function(value) - return { - "call", - { - value - } - } -end -local join_chain -join_chain = function(callee, args) - if #args == 0 then - return callee - end - args = { - "call", - args - } - if ntype(callee) == "chain" then - table.insert(callee, args) - return callee - end - return { - "chain", - callee, - args - } -end -local wrap_decorator -wrap_decorator = function(stm, dec) - if not (dec) then - return stm - end - return { - "decorated", - stm, - dec - } -end -local check_lua_string -check_lua_string = function(str, pos, right, left) - return #left == #right -end -local self_assign -self_assign = function(name, pos) - return { - { - "key_literal", - name - }, - { - "ref", - name, - [-1] = pos - } - } -end -return { - Indent = Indent, - Cut = Cut, - ensure = ensure, - extract_line = extract_line, - mark = mark, - pos = pos, - flatten_or_mark = flatten_or_mark, - is_assignable = is_assignable, - check_assignable = check_assignable, - format_assign = format_assign, - format_single_assign = format_single_assign, - sym = sym, - symx = symx, - simple_string = simple_string, - wrap_func_arg = wrap_func_arg, - join_chain = join_chain, - wrap_decorator = wrap_decorator, - check_lua_string = check_lua_string, - self_assign = self_assign, - got = got, - show_line_position = show_line_position -} diff --git a/moonscript/parse/util.moon b/moonscript/parse/util.moon deleted file mode 100644 index 7ff72820..00000000 --- a/moonscript/parse/util.moon +++ /dev/null @@ -1,185 +0,0 @@ - -import unpack from require "moonscript.util" -import P, C, S, Cp, Cmt, V from require "lpeg" -import ntype, is_assignable from require "moonscript.types" -import Space from require "moonscript.parse.literals" - --- captures an indentation, returns indent depth -Indent = C(S"\t "^0) / (str) -> - with sum = 0 - for v in str\gmatch "[\t ]" - switch v - when " " - sum += 1 - when "\t" - sum += 4 - - --- causes pattern in progress to be rejected --- can't have P(false) because it causes preceding patterns not to run -Cut = P -> false - --- ensures finally runs regardless of whether pattern fails or passes -ensure = (patt, finally) -> - patt * finally + finally * Cut - --- take rest of line from pos out of str -extract_line = (str, start_pos) -> - str = str\sub start_pos - if m = str\match "^(.-)\n" - return m - - str\match "^.-$" - --- print the line with a token showing the position -show_line_position = (str, pos, context=true) -> - lines = { {} } - for c in str\gmatch "." - lines[#lines] or= {} - table.insert lines[#lines], c - if c == "\n" - lines[#lines + 1] = {} - - for i, line in ipairs lines - lines[i] = table.concat line - - local out - - remaining = pos - 1 - for k, line in ipairs lines - if remaining < #line - left = line\sub 1, remaining - right = line\sub remaining + 1 - out = { - "#{left}◉#{right}" - } - - if context - if before = lines[k - 1] - table.insert out, 1, before - - if after = lines[k + 1] - table.insert out, after - - break - else - remaining -= #line - - - return "-" unless out - - out = table.concat out - (out\gsub "\n*$", "") - --- used to identify a capture with a label -mark = (name) -> - (...) -> {name, ...} - --- wraps pattern to capture pos into node --- pos is the character offset from the buffer where the node was parsed from. --- Used to generate error messages -pos = (patt) -> - (Cp! * patt) / (pos, value) -> - if type(value) == "table" - value[-1] = pos - value - --- generates a debug pattern that always succeeds and prints out where we are --- in the buffer with a label -got = (what, context=true) -> - Cmt "", (str, pos) -> - print "++ got #{what}", "[#{show_line_position str, pos, context}]" - true - --- converts 1 element array to its value, otherwise marks it -flatten_or_mark = (name) -> - (tbl) -> - return tbl[1] if #tbl == 1 - table.insert tbl, 1, name - tbl - -check_assignable = (str, pos, value) -> - if is_assignable value - true, value - else - false - --- joins the two parts of an assign parse into a single node -format_assign = do - flatten_explist = flatten_or_mark "explist" - - (lhs_exps, assign) -> - unless assign - return flatten_explist lhs_exps - - for assign_exp in *lhs_exps - unless is_assignable assign_exp - error {assign_exp, "left hand expression is not assignable"} - - t = ntype assign - switch t - when "assign" - {"assign", lhs_exps, unpack assign, 2} - when "update" - {"update", lhs_exps[1], unpack assign, 2} - else - error "unknown assign expression: #{t}" - --- helper for if statement, which only has single lhs -format_single_assign = (lhs, assign) -> - if assign - format_assign {lhs}, assign - else - lhs - - --- a symbol -sym = (chars) -> Space * chars --- a symbol that doesn't accept whitespace before it -symx = (chars) -> chars - --- a constructor for quote delimited strings -simple_string = (delim, allow_interpolation) -> - inner = P("\\#{delim}") + "\\\\" + (1 - P delim) - - inner = if allow_interpolation - interp = symx'#{' * V"Exp" * sym'}' - -- string content stops at every #{ so a malformed interpolation fails - -- the parse instead of falling through to literal text - (C((inner - symx'#{')^1) + interp / mark"interpolate")^0 - else - C inner^0 - - C(symx(delim)) * inner * sym(delim) / mark"string" - --- wraps a single value in format needed to be passed as function arguments -wrap_func_arg = (value) -> {"call", {value}} - --- chains are parsed in two captures, the chain and then the open arguments --- if there are open arguments, then append them to the end of the chain as a call -join_chain = (callee, args) -> - return callee if #args == 0 - args = {"call", args} - - if ntype(callee) == "chain" - table.insert callee, args - return callee - - {"chain", callee, args} - --- constructor for decorator node -wrap_decorator = (stm, dec) -> - return stm unless dec - {"decorated", stm, dec} - -check_lua_string = (str, pos, right, left) -> - #left == #right - --- constructor for :name self assignments in table literals -self_assign = (name, pos) -> - {{"key_literal", name}, {"ref", name, [-1]: pos}} - -{ :Indent, :Cut, :ensure, :extract_line, :mark, :pos, :flatten_or_mark, - :is_assignable, :check_assignable, :format_assign, :format_single_assign, - :sym, :symx, :simple_string, :wrap_func_arg, :join_chain, :wrap_decorator, - :check_lua_string, :self_assign, :got, :show_line_position } diff --git a/moonscript/transform/value.lua b/moonscript/transform/value.lua index fa016a95..4b49cd0c 100644 --- a/moonscript/transform/value.lua +++ b/moonscript/transform/value.lua @@ -157,7 +157,7 @@ return Transformer({ if "self" == _exp_0 or "self_class" == _exp_0 then bound_names[arg[1][2]] = true elseif "table" == _exp_0 then - local _ = nil + local _scrap_0 = nil else if type(arg[1]) == "string" then bound_names[arg[1]] = true diff --git a/moonscript/version.lua b/moonscript/version.lua index db7b74a6..006ef970 100644 --- a/moonscript/version.lua +++ b/moonscript/version.lua @@ -1,4 +1,4 @@ -local version = "0.7.0" +local version = "0.8.0" return { version = version, print_version = function() diff --git a/moonscript/version.moon b/moonscript/version.moon index 3dbf03a3..7e76451d 100644 --- a/moonscript/version.moon +++ b/moonscript/version.moon @@ -1,5 +1,5 @@ -version = "0.7.0" +version = "0.8.0" { version: version, diff --git a/spec/helpers.moon b/spec/helpers.moon index caf885c2..808381e3 100644 --- a/spec/helpers.moon +++ b/spec/helpers.moon @@ -36,6 +36,12 @@ with_dev = (fn) -> mod\match("moon%.") or mod == "moon" if testable + -- the compiled parser can't be loaded from source; resolve it + -- through the regular require (package.preload from the + -- use_slow_parser helper, ./?.so, or the installed rock) + if mod == "moonscript.parse.native" + return old_require mod + fname = assert loader(mod), "failed to find module: #{mod}" dev_cache[mod] = assert(loadfile fname)! return dev_cache[mod] diff --git a/spec/parser_spec.moon b/spec/parser_spec.moon new file mode 100644 index 00000000..a1dc0dac --- /dev/null +++ b/spec/parser_spec.moon @@ -0,0 +1,151 @@ +-- Unit tests for the parser. Expected trees are written out inline, +-- including [-1] position annotations. The lang_spec corpus covers whole +-- files from parse to compiled output; these are quick hand-checked cases. + +import with_dev from require "spec.helpers" + +describe "moonscript.parse", -> + local parse + + with_dev -> + parse = require "moonscript.parse" + + it "parses assignment", -> + assert.same { + {"assign" + {{"ref", "x", [-1]: 1}} + {{"number", "5", [-1]: 4}} + [-1]: 1} + }, parse.string "x = 5" + + it "parses an open call", -> + assert.same { + {"chain" + {"ref", "print", [-1]: 1} + {"call", {{"ref", "x", [-1]: 6}}} + [-1]: 1} + }, parse.string "print x" + + it "parses table with self-assign and string key", -> + assert.same { + {"assign" + {{"ref", "t", [-1]: 1}} + {{"table", { + {{"key_literal", "name"}, {"ref", "name", [-1]: 11}} + {{"string", '"', "k"}, {"ref", "v", [-1]: 17}} + }, [-1]: 4}} + [-1]: 1} + }, parse.string [[t = {:name, "k": v}]] + + it "parses a function literal with binary op body", -> + assert.same { + {"assign" + {{"ref", "f", [-1]: 1}} + {{"fndef", {{"a"}}, {}, "slim", { + {"exp", {"ref", "a", [-1]: 11}, "+", {"number", "1", [-1]: 15}, [-1]: 11} + }, [-1]: 4}} + [-1]: 1} + }, parse.string "f = (a) -> a + 1" + + it "parses an indented block", -> + assert.same { + {"if", {"ref", "x", [-1]: 3}, { + {"chain", {"ref", "y", [-1]: 8}, {"call", {}}, [-1]: 8} + }, [-1]: 1} + }, parse.string "if x\n y!" + + it "parses lua strings, reconstructing the open delimiter", -> + assert.same { + {"assign" + {{"ref", "x", [-1]: 1}} + {{"string", "[==[", "str", [-1]: 4}} + [-1]: 1} + }, parse.string "x = [==[str]==]" + + it "parses an anonymous class with a nil name slot", -> + tree = assert parse.string "x = class" + class_node = tree[1][3][1] + assert.same "class", class_node[1] + assert.is_nil class_node[2] + assert.same "", class_node[3] + assert.same {}, class_node[4] + + it "parses an empty file", -> + assert.same {}, parse.string "" + + it "parses a comment-only file", -> + assert.same {}, parse.string "-- nothing here" + + it "fails on unbalanced parens", -> + tree, err = parse.string "x = (a + b" + assert.is_nil tree + assert.is_string err + + it "fails on a bad outdent", -> + tree = parse.string "if x\n y\n z" + assert.is_nil tree + + it "rejects a non-assignable left hand side", -> + tree, err = parse.string "f! = 5" + assert.is_nil tree + assert.matches "not assignable", err + assert.matches "line 1", err + + it "reports a line position for parse failures", -> + tree, err = parse.string "x = 1\ny = 2\nz = (a +" + assert.is_nil tree + assert.matches "line 3", err + + tree, err = parse.string 'x = "hello\ny = 1' + assert.is_nil tree + assert.matches "line 2", err + + tree, err = parse.string "import a from" + assert.is_nil tree + assert.matches "line 1", err + + -- regression: T() labels were tried in this grammar and removed. Value + -- tries Comprehension before String, so at "[[" the parser attempts to + -- parse string content as code; a label reached during such an attempt + -- rejected valid programs like these. + it "parses code-like content inside long strings", -> + assert.is_table parse.string "y = [[if x then import a]] .. z" + assert.is_table parse.string "x = [[=[hi]] .. 1" + assert.is_table parse.string [=[x = y .. [[Flow:extend("]] .. z .. [[")]] .. w]=] + + it "keeps the parser reusable after a failed parse", -> + tree = parse.string "x = (" + assert.is_nil tree + + assert.same { + {"assign" + {{"ref", "x", [-1]: 1}} + {{"number", "1", [-1]: 4}} + [-1]: 1} + }, parse.string "x = 1" + + it "returns nil, err instead of raising on the recursion depth limit", -> + str = ("(")\rep 6000 + tree, err = parse.string str + assert.is_nil tree + assert.matches "max recursion depth", err + + it "disables do expressions inside loop headers", -> + -- `do` after the while condition is the block keyword, not a do-expression + tree = assert parse.string "while x do print 1" + assert.same "while", tree[1][1] + + -- but a do-expression is fine in normal expression position + tree = assert parse.string "x = do\n 5" + assert.same "do", tree[1][3][1][1] + + it "handles interpolation containing a lua string", -> + tree = assert parse.string [=[x = "a#{ [[long]] }b"]=] + str = tree[1][3][1] + assert.same "string", str[1] + assert.same "a", str[3] + assert.same "interpolate", str[4][1] + assert.same "string", str[4][2][1] + assert.same "[[", str[4][2][2] + assert.same "long", str[4][2][3] + assert.same "b", str[5] diff --git a/spec/use_slow_parser.moon b/spec/use_slow_parser.moon new file mode 100644 index 00000000..a6e54670 --- /dev/null +++ b/spec/use_slow_parser.moon @@ -0,0 +1,7 @@ +-- busted helper (busted --helper=spec/use_slow_parser.moon) that runs the +-- suite against the pure Lua parser in place of the native C module. busted +-- loads moonscript, and with it the native parser, before helpers run, so +-- the package.loaded entry must be replaced as well +slow = dofile "moonscript/parse/slow.lua" +package.loaded["moonscript.parse.native"] = slow +package.preload["moonscript.parse.native"] = -> slow From 3218169242920c8fc11a4f40403bbb0f8a9dba58 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Mon, 27 Jul 2026 09:27:33 -0700 Subject: [PATCH 552/554] regenerate parser --- moonscript/parse/native.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/moonscript/parse/native.c b/moonscript/parse/native.c index 10d21986..7f07c1bf 100644 --- a/moonscript/parse/native.c +++ b/moonscript/parse/native.c @@ -568,7 +568,7 @@ static void __const_init(lua_State *L) { __const_refs[50] = luaL_ref(L, LUA_REGISTRYINDEX); lua_pushlstring(L, "with", 4); __const_refs[51] = luaL_ref(L, LUA_REGISTRYINDEX); - lua_pushnumber(L, 1); + lua_pushinteger(L, 1); __const_refs[52] = luaL_ref(L, LUA_REGISTRYINDEX); for (int i = 0; __cg_names[i] != NULL; i++) { lua_pushstring(L, __cg_names[i]); From 7e0628a43a3de1f09fb0844878e9e71f748741a7 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Mon, 27 Jul 2026 09:41:35 -0700 Subject: [PATCH 553/554] ensure native parser callback modules are loaded before the native parser --- .github/workflows/binaries.yml | 2 +- Makefile | 2 +- bin/binaries/moonscript.c | 22 +++++++++++++++------- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/.github/workflows/binaries.yml b/.github/workflows/binaries.yml index 40c3b449..bf97b77d 100644 --- a/.github/workflows/binaries.yml +++ b/.github/workflows/binaries.yml @@ -25,7 +25,7 @@ jobs: - name: Generate moonscript.h run: | - bin/splat.moon -l moonscript -x moonscript.parse.slow -x moonscript.parse.grammar moonscript moon > moonscript.lua + bin/splat.moon -x moonscript.parse.slow -x moonscript.parse.grammar moonscript moon > moonscript.lua xxd -i moonscript.lua > bin/binaries/moonscript.h - name: Generate moon.h diff --git a/Makefile b/Makefile index c841f5de..f2768176 100644 --- a/Makefile +++ b/Makefile @@ -83,7 +83,7 @@ luafilesystem-$(LFS_VERSION)/src/lfs.c: tar -xzf luafilesystem.tar.gz bin/binaries/moonscript.h: moonscript/*.lua moon/*.lua - bin/splat.moon -l moonscript -x moonscript.parse.slow -x moonscript.parse.grammar moonscript moon > moonscript.lua + bin/splat.moon -x moonscript.parse.slow -x moonscript.parse.grammar moonscript moon > moonscript.lua xxd -i moonscript.lua > $@ rm moonscript.lua diff --git a/bin/binaries/moonscript.c b/bin/binaries/moonscript.c index 2769008d..53f4fa72 100644 --- a/bin/binaries/moonscript.c +++ b/bin/binaries/moonscript.c @@ -29,17 +29,25 @@ LUALIB_API int luaopen_moonscript(lua_State *l) { luaopen_lpeg(l); setloaded(l, "lpeg"); - luaopen_moonscript_parse_native(l); - setloaded(l, "moonscript.parse.native"); - // Load argparse (splat output sets up package.preload) if (luaL_loadbuffer(l, (const char *)argparse_lua, argparse_lua_len, "argparse.lua") == 0) { lua_call(l, 0, 0); } - if (luaL_loadbuffer(l, (const char *)moonscript_lua, moonscript_lua_len, "moonscript.lua") == 0) { - lua_call(l, 0, 1); - return 1; + // Register the moonscript modules into package.preload + if (luaL_loadbuffer(l, (const char *)moonscript_lua, moonscript_lua_len, "moonscript.lua") != 0) { + return 0; } - return 0; + lua_call(l, 0, 0); + + // The native parser runs its callback chunks at load, and those require + // moonscript.parse.tree: package.preload must be populated first or the + // require escapes to the filesystem + luaopen_moonscript_parse_native(l); + setloaded(l, "moonscript.parse.native"); + + lua_getglobal(l, "require"); + lua_pushstring(l, "moonscript"); + lua_call(l, 1, 1); + return 1; } From 60a07f80a9b87da85db49f4e0b2283fb821e0e85 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Mon, 3 Aug 2026 10:25:05 -0700 Subject: [PATCH 554/554] fix example for local hoisting --- CHANGELOG.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ffc8f64..54dfa0fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -324,10 +324,10 @@ parent's name. ```moonscript class Counter - local count - count = 0 + local cache - inc: => count += 1 + -- previously `cache` local would not be lexically available in the method + update: => cache or= "something..." ``` ## Bug Fixes