aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--code_obj.lua41
-rw-r--r--code_obj.moon36
-rw-r--r--files.lua3
-rw-r--r--files.moon1
-rw-r--r--nomsu_compiler.lua648
-rw-r--r--nomsu_compiler.moon473
-rw-r--r--parser.lua18
-rw-r--r--parser.moon7
-rwxr-xr-xtools/autoformat.nom17
9 files changed, 643 insertions, 601 deletions
diff --git a/code_obj.lua b/code_obj.lua
index b67e78d..470cd11 100644
--- a/code_obj.lua
+++ b/code_obj.lua
@@ -80,6 +80,11 @@ do
local _class_0
local _base_0 = {
is_code = true,
+ dirty = function(self)
+ self.__str = nil
+ self._trailing_line_len = nil
+ self._is_multiline = nil
+ end,
append = function(self, ...)
local n = select("#", ...)
local match = string.match
@@ -104,8 +109,7 @@ do
break
end
end
- self.__str = nil
- self._trailing_line_len = nil
+ return self:dirty()
end,
trailing_line_len = function(self)
if self._trailing_line_len == nil then
@@ -117,19 +121,38 @@ do
do
local line = match(b, "\n([^\n]*)$")
if line then
- return len + #line
+ len = len + #line
+ break
else
len = len + #b
end
end
else
len = len + b:trailing_line_len()
+ if b:is_multiline() then
+ break
+ end
end
end
self._trailing_line_len = len
end
return self._trailing_line_len
end,
+ is_multiline = function(self)
+ if self._is_multiline == nil then
+ local match = string.match
+ self._is_multiline = false
+ local _list_0 = self.bits
+ for _index_0 = 1, #_list_0 do
+ local b = _list_0[_index_0]
+ if type(b) ~= 'string' or match(b, "\n") then
+ self._is_multiline = true
+ break
+ end
+ end
+ end
+ return self._is_multiline
+ end,
concat_append = function(self, values, joiner, wrapping_joiner)
wrapping_joiner = wrapping_joiner or joiner
local match = string.match
@@ -154,8 +177,7 @@ do
line_len = line_len + #b
end
end
- self.__str = nil
- self._trailing_line_len = nil
+ return self:dirty()
end,
prepend = function(self, ...)
local n = select("#", ...)
@@ -166,8 +188,7 @@ do
for i = 1, n do
bits[i] = select(i, ...)
end
- self.__str = nil
- self._trailing_line_len = nil
+ return self:dirty()
end
}
_base_0.__index = _base_0
@@ -223,8 +244,7 @@ do
seen[var] = true
end
end
- self.__str = nil
- self._trailing_line_len = nil
+ return self:dirty()
end,
remove_free_vars = function(self, vars)
if not (#vars > 0) then
@@ -256,8 +276,7 @@ do
end
end
end
- self.__str = nil
- self._trailing_line_len = nil
+ return self:dirty()
end,
declare_locals = function(self, to_declare)
if to_declare == nil then
diff --git a/code_obj.moon b/code_obj.moon
index 9bfa9a5..35d1027 100644
--- a/code_obj.moon
+++ b/code_obj.moon
@@ -51,6 +51,11 @@ class Code
@source = Source\from_string(@source)
assert(@source and Source\is_instance(@source), "Source has the wrong type")
@append(...)
+
+ dirty: =>
+ @__str = nil
+ @_trailing_line_len = nil
+ @_is_multiline = nil
append: (...)=>
n = select("#",...)
@@ -64,8 +69,7 @@ class Code
bits[#bits+1] = b
if type(b) != 'string' and not (type(b) == 'table' and b.is_code)
b = repr(b)
- @__str = nil
- @_trailing_line_len = nil
+ @dirty!
trailing_line_len: =>
if @_trailing_line_len == nil
@@ -75,13 +79,25 @@ class Code
b = bits[i]
if type(b) == 'string'
if line = match(b, "\n([^\n]*)$")
- return len + #line
+ len += #line
+ break
else len += #b
else
len += b\trailing_line_len!
+ break if b\is_multiline!
@_trailing_line_len = len
return @_trailing_line_len
-
+
+ is_multiline: =>
+ if @_is_multiline == nil
+ match = string.match
+ @_is_multiline = false
+ for b in *@bits
+ if type(b) != 'string' or match(b, "\n")
+ @_is_multiline = true
+ break
+ return @_is_multiline
+
concat_append: (values, joiner, wrapping_joiner)=>
wrapping_joiner or= joiner
match = string.match
@@ -102,8 +118,7 @@ class Code
line_len = #line
else
line_len += #b
- @__str = nil
- @_trailing_line_len = nil
+ @dirty!
prepend: (...)=>
n = select("#",...)
@@ -112,8 +127,7 @@ class Code
bits[i] = bits[i-n]
for i=1,n
bits[i] = select(i, ...)
- @__str = nil
- @_trailing_line_len = nil
+ @dirty!
class LuaCode extends Code
new: (...)=>
@@ -134,8 +148,7 @@ class LuaCode extends Code
unless seen[var]
@free_vars[#@free_vars+1] = var
seen[var] = true
- @__str = nil
- @_trailing_line_len = nil
+ @dirty!
remove_free_vars: (vars)=>
return unless #vars > 0
@@ -154,8 +167,7 @@ class LuaCode extends Code
for b in *lua.bits
if type(b) != 'string'
stack[#stack+1] = b
- @__str = nil
- @_trailing_line_len = nil
+ @dirty!
declare_locals: (to_declare=nil)=>
if to_declare == nil
diff --git a/files.lua b/files.lua
index 65a8e1b..ef5c8c1 100644
--- a/files.lua
+++ b/files.lua
@@ -160,6 +160,9 @@ files.walk = function(path, flush_cache)
end
local iter
iter = function(_files, i)
+ if not (_files) then
+ return
+ end
i = i + 1
do
local f = _files[i]
diff --git a/files.moon b/files.moon
index 6f06c8c..ad1956b 100644
--- a/files.moon
+++ b/files.moon
@@ -98,6 +98,7 @@ files.walk = (path, flush_cache=false)->
for nomsupath in package.nomsupath\gmatch("[^;]+")
if _files = browse(nomsupath.."/"..path) then break
iter = (_files, i)->
+ return unless _files
i += 1
if f = _files[i]
return i, f
diff --git a/nomsu_compiler.lua b/nomsu_compiler.lua
index 652a5c8..bdaa726 100644
--- a/nomsu_compiler.lua
+++ b/nomsu_compiler.lua
@@ -733,7 +733,147 @@ do
return error("Unknown type: " .. tostring(tree.type))
end
end
- local MIN_COLON_LEN = 20
+ NomsuCompiler.tree_to_inline_nomsu = function(self, tree, parenthesize_blocks)
+ if parenthesize_blocks == nil then
+ parenthesize_blocks = false
+ end
+ local _exp_0 = tree.type
+ if "FileChunks" == _exp_0 then
+ return error("Cannot inline a FileChunks")
+ elseif "Action" == _exp_0 then
+ local nomsu = NomsuCode(tree.source)
+ for i, bit in ipairs(tree) do
+ if type(bit) == "string" then
+ local clump_words = (type(tree[i - 1]) == 'string' and Parser.is_operator(bit) ~= Parser.is_operator(tree[i - 1]))
+ if i > 1 and not clump_words then
+ nomsu:append(" ")
+ end
+ nomsu:append(bit)
+ else
+ local arg_nomsu = self:tree_to_inline_nomsu(bit, parenthesize_blocks or (i == 1 or i < #tree))
+ if not (tostring(arg_nomsu):match("^:") or i == 1) then
+ nomsu:append(" ")
+ end
+ if bit.type == "Action" then
+ arg_nomsu:parenthesize()
+ end
+ nomsu:append(arg_nomsu)
+ end
+ end
+ return nomsu
+ elseif "EscapedNomsu" == _exp_0 then
+ local inner_nomsu = self:tree_to_inline_nomsu(tree[1])
+ if tree[1].type == "List" or tree[1].type == "Dict" or tree[1].type == "Var" then
+ return NomsuCode(tree.source, "\\", inner_nomsu)
+ else
+ return NomsuCode(tree.source, "\\(", inner_nomsu, ")")
+ end
+ elseif "Block" == _exp_0 then
+ local nomsu = NomsuCode(tree.source, ":")
+ for i, line in ipairs(tree) do
+ nomsu:append(i == 1 and " " or "; ")
+ nomsu:append(self:tree_to_inline_nomsu(line, i == 1 or i < #tree))
+ end
+ if #tree > 1 or parenthesize_blocks then
+ nomsu:parenthesize()
+ end
+ return nomsu
+ elseif "Text" == _exp_0 then
+ local make_text
+ make_text = function(tree)
+ local nomsu = NomsuCode(tree.source)
+ for i, bit in ipairs(tree) do
+ if type(bit) == 'string' then
+ bit = Parser.inline_escape(bit)
+ nomsu:append(bit)
+ elseif bit.type == "Text" then
+ nomsu:append(make_text(bit))
+ else
+ local interp_nomsu = self:tree_to_inline_nomsu(bit)
+ if bit.type ~= "Var" and bit.type ~= "List" and bit.type ~= "Dict" then
+ interp_nomsu:parenthesize()
+ elseif bit.type == "Var" and type(tree[i + 1]) == 'string' and not match(tree[i + 1], "^[ \n\t,.:;#(){}[%]]") then
+ interp_nomsu:parenthesize()
+ end
+ nomsu:append("\\", interp_nomsu)
+ end
+ end
+ return nomsu
+ end
+ return NomsuCode(tree.source, '"', make_text(tree), '"')
+ elseif "List" == _exp_0 then
+ local nomsu = NomsuCode(tree.source, "[")
+ for i, item in ipairs(tree) do
+ if i > 1 then
+ nomsu:append(", ")
+ end
+ nomsu:append(self:tree_to_inline_nomsu(item))
+ end
+ nomsu:append("]")
+ return nomsu
+ elseif "Dict" == _exp_0 then
+ local nomsu = NomsuCode(tree.source, "{")
+ for i, entry in ipairs(tree) do
+ if i > 1 then
+ nomsu:append(", ")
+ end
+ nomsu:append(self:tree_to_inline_nomsu(entry))
+ end
+ nomsu:append("}")
+ return nomsu
+ elseif "DictEntry" == _exp_0 then
+ local key, value = tree[1], tree[2]
+ local key_nomsu
+ if key.type == "Text" and #key == 1 and Parser.is_identifier(key[1]) then
+ key_nomsu = NomsuCode(key.source, key[1])
+ else
+ key_nomsu = self:tree_to_inline_nomsu(key)
+ end
+ if key.type == "Action" or key.type == "Block" then
+ key_nomsu:parenthesize()
+ end
+ local value_nomsu
+ if value then
+ value_nomsu = self:tree_to_inline_nomsu(value)
+ else
+ value_nomsu = NomsuCode(tree.source, "")
+ end
+ assert(value.type ~= "Block", "Didn't expect to find a Block as a value in a dict")
+ if value.type == "Block" then
+ value_nomsu:parenthesize()
+ end
+ return NomsuCode(tree.source, key_nomsu, ": ", value_nomsu)
+ elseif "IndexChain" == _exp_0 then
+ local nomsu = NomsuCode(tree.source)
+ for i, bit in ipairs(tree) do
+ if i > 1 then
+ nomsu:append(".")
+ end
+ local bit_nomsu
+ if bit.type == "Text" and #bit == 1 and type(bit[1]) == 'string' and Parser.is_identifier(bit[1]) then
+ bit_nomsu = bit[1]
+ else
+ bit_nomsu = self:tree_to_inline_nomsu(bit)
+ end
+ local _exp_1 = bit.type
+ if "Action" == _exp_1 or "Block" == _exp_1 or "IndexChain" == _exp_1 then
+ bit_nomsu:parenthesize()
+ elseif "Number" == _exp_1 then
+ if i < #tree then
+ bit_nomsu:parenthesize()
+ end
+ end
+ nomsu:append(bit_nomsu)
+ end
+ return nomsu
+ elseif "Number" == _exp_0 then
+ return NomsuCode(tree.source, tostring(tree[1]))
+ elseif "Var" == _exp_0 then
+ return NomsuCode(tree.source, "%", tree[1])
+ else
+ return error("Unknown type: " .. tostring(tree.type))
+ end
+ end
NomsuCompiler.tree_to_nomsu = function(self, tree, options)
options = options or { }
options.consumed_comments = options.consumed_comments or { }
@@ -787,14 +927,10 @@ do
recurse = function(t, opts)
opts = opts or { }
opts.consumed_comments = options.consumed_comments
- opts.inside_multiblock = opts.inside_multiblock or options.inside_multiblock
return self:tree_to_nomsu(t, opts)
end
local _exp_0 = tree.type
if "FileChunks" == _exp_0 then
- if options.inline then
- error("Cannot inline a FileChunks")
- end
local nomsu = NomsuCode(tree.source, pop_comments(tree.source.start))
for i, chunk in ipairs(tree) do
if i > 1 then
@@ -808,108 +944,68 @@ do
nomsu:append(pop_comments(tree.source.stop, '\n'))
return nomsu
elseif "Action" == _exp_0 then
- if options.inline then
- local nomsu = NomsuCode(tree.source)
- for i, bit in ipairs(tree) do
- if type(bit) == "string" then
- if i > 1 and not (type(tree[i - 1]) == 'string' and Parser.is_operator(bit) ~= Parser.is_operator(tree[i - 1])) then
- nomsu:append(" ")
- end
- nomsu:append(bit)
+ local pos = tree.source.start
+ local nomsu = NomsuCode(tree.source, pop_comments(pos))
+ local next_space = ""
+ for i, bit in ipairs(tree) do
+ if match(next_space, '\n') then
+ nomsu:append(pop_comments(pos, '\n'))
+ end
+ if type(bit) == "string" then
+ if next_space == ' ' and (type(tree[i - 1]) == 'string' and Parser.is_operator(bit) ~= Parser.is_operator(tree[i - 1])) then
+ next_space = ''
+ end
+ nomsu:append(next_space, bit)
+ next_space = " "
+ else
+ local arg_nomsu
+ if bit.type == "Block" and #bit > 1 then
+ arg_nomsu = nil
else
- local arg_nomsu = recurse(bit, {
- inline = true
- })
- if not (arg_nomsu) then
- return nil
- end
+ arg_nomsu = self:tree_to_inline_nomsu(bit)
+ end
+ if bit.type == "Text" and tostring(arg_nomsu) ~= '"\\n"' and tostring(arg_nomsu):match("\\n") then
+ arg_nomsu = nil
+ end
+ if bit.type == "Block" then
+ next_space = match(next_space, "[^ ]*")
+ end
+ nomsu:append(next_space)
+ if arg_nomsu and nomsu:trailing_line_len() + #tostring(arg_nomsu) < MAX_LINE then
if bit.type == "Block" then
- if i == 1 or i < #tree or options.inside_multiblock then
- if i > 1 then
- nomsu:append(" ")
- end
- arg_nomsu:parenthesize()
- end
nomsu:append(arg_nomsu)
+ next_space = "\n.."
else
- if i > 1 then
- nomsu:append(" ")
- end
if bit.type == "Action" then
arg_nomsu:parenthesize()
end
nomsu:append(arg_nomsu)
+ next_space = " "
end
- end
- end
- return nomsu
- else
- local pos = tree.source.start
- local nomsu = NomsuCode(tree.source, pop_comments(pos))
- local next_space = ""
- for i, bit in ipairs(tree) do
- if match(next_space, '\n') then
- nomsu:append(pop_comments(pos, '\n'))
- end
- if type(bit) == "string" then
- if next_space == ' ' and (type(tree[i - 1]) == 'string' and Parser.is_operator(bit) ~= Parser.is_operator(tree[i - 1])) then
- next_space = ''
- end
- nomsu:append(next_space, bit)
- next_space = " "
else
- local arg_nomsu
- if bit.type == "Block" and #bit > 1 then
- arg_nomsu = nil
- else
- arg_nomsu = assert(recurse(bit, {
- inline = true
- }))
- end
- if tostring(arg_nomsu) ~= '"\\n"' and tostring(arg_nomsu):match("\\n") then
- arg_nomsu = nil
- end
- if bit.type == "Block" then
- next_space = match(next_space, "[^ ]*")
- end
- nomsu:append(next_space)
- if arg_nomsu and nomsu:trailing_line_len() + #tostring(arg_nomsu) < MAX_LINE then
- if bit.type == "Block" then
- nomsu:append(arg_nomsu)
- next_space = "\n.."
- else
- if bit.type == "Action" then
- arg_nomsu:parenthesize()
- end
- nomsu:append(arg_nomsu)
- next_space = " "
- end
+ arg_nomsu = assert(recurse(bit))
+ local _exp_1 = bit.type
+ if "List" == _exp_1 or "Dict" == _exp_1 or "Text" == _exp_1 or "Block" == _exp_1 or "EscapedNomsu" == _exp_1 then
+ nomsu:append(arg_nomsu)
else
- arg_nomsu = assert(recurse(bit))
- if bit.type ~= "List" and bit.type ~= "Dict" and bit.type ~= "Text" and bit.type ~= "Block" then
- nomsu:append(NomsuCode(bit.source, "(..)\n ", pop_comments(bit.source.start), arg_nomsu))
- else
- nomsu:append(arg_nomsu)
- end
- next_space = "\n.."
+ nomsu:append(NomsuCode(bit.source, "(..)\n ", pop_comments(bit.source.start), arg_nomsu))
end
- pos = bit.source.stop
- end
- if next_space == " " and nomsu:trailing_line_len() > MAX_LINE then
next_space = "\n.."
end
+ pos = bit.source.stop
+ end
+ if next_space == " " and nomsu:trailing_line_len() > MAX_LINE then
+ next_space = "\n.."
end
- nomsu:append(pop_comments(pos, '\n'))
- return nomsu
end
+ nomsu:append(pop_comments(pos, '\n'))
+ return nomsu
elseif "EscapedNomsu" == _exp_0 then
- local nomsu = NomsuCode(tree.source, "\\(", assert(recurse(tree[1], {
- inline = true
- })), ")")
- if options.inline or #tostring(nomsu) <= MAX_LINE then
- return nomsu
+ local inline_nomsu = self:tree_to_inline_nomsu(tree)
+ if #tostring(inline_nomsu) <= MAX_LINE then
+ return inline_nomsu
end
- nomsu = assert(recurse(tree[1]))
+ local nomsu = recurse(tree[1])
local _exp_1 = tree[1].type
if "List" == _exp_1 or "Dict" == _exp_1 or "Text" == _exp_1 or "Block" == _exp_1 then
return NomsuCode(tree.source, "\\", nomsu)
@@ -917,313 +1013,177 @@ do
return NomsuCode(tree.source, "\\(..)\n ", pop_comments(tree.source.start), nomsu)
end
elseif "Block" == _exp_0 then
- if options.inline then
- local nomsu = NomsuCode(tree.source, ":")
- for i, line in ipairs(tree) do
- nomsu:append(i == 1 and " " or "; ")
- nomsu:append(assert(recurse(line, {
- inline = true,
- inside_multiblock = true
- })))
- end
- return nomsu
- end
local nomsu = NomsuCode(tree.source, pop_comments(tree.source.start))
for i, line in ipairs(tree) do
nomsu:append(pop_comments(line.source.start, '\n'))
- line = assert(recurse(line), "Could not convert line to nomsu")
- nomsu:append(line)
+ local line_nomsu = recurse(line)
+ nomsu:append(line_nomsu)
if i < #tree then
- nomsu:append("\n")
- if match(tostring(line), "\n") then
- nomsu:append("\n")
- end
+ nomsu:append(line_nomsu:is_multiline() and "\n\n" or "\n")
end
end
nomsu:append(pop_comments(tree.source.stop, '\n'))
return options.top and nomsu or NomsuCode(tree.source, ":\n ", nomsu)
elseif "Text" == _exp_0 then
- if options.inline then
- local make_text
- make_text = function(tree)
- local nomsu = NomsuCode(tree.source)
- for i, bit in ipairs(tree) do
- if type(bit) == 'string' then
- bit = (gsub(gsub(gsub(bit, "\\", "\\\\"), "\n", "\\n"), '"', '\\"'))
- bit = gsub(bit, "%G", (function(c)
- return c == ' ' and c or "\\" .. tostring(c:byte())
- end))
- nomsu:append(bit)
- elseif bit.type == "Text" then
- nomsu:append(make_text(bit))
- else
- local interp_nomsu = assert(recurse(bit, {
- inline = true
- }))
- if bit.type ~= "Var" and bit.type ~= "List" and bit.type ~= "Dict" then
- interp_nomsu:parenthesize()
- elseif bit.type == "Var" and type(tree[i + 1]) == 'string' and not match(tree[i + 1], "^[ \n\t,.:;#(){}[%]]") then
- interp_nomsu:parenthesize()
+ local inline_version = self:tree_to_inline_nomsu(tree)
+ if inline_version and #tostring(inline_version) <= MAX_LINE then
+ return inline_version
+ end
+ local make_text
+ make_text = function(tree)
+ local nomsu = NomsuCode(tree.source)
+ for i, bit in ipairs(tree) do
+ if type(bit) == 'string' then
+ bit = Parser.escape(bit)
+ local bit_lines = files.get_lines(bit)
+ for j, line in ipairs(bit_lines) do
+ if j > 1 then
+ nomsu:append("\n")
end
- nomsu:append("\\", interp_nomsu)
- end
- end
- return nomsu
- end
- return NomsuCode(tree.source, '"', make_text(tree), '"')
- else
- local inline_version = recurse(tree, {
- inline = true
- })
- if inline_version and #tostring(inline_version) <= MAX_LINE then
- return inline_version
- end
- local make_text
- make_text = function(tree)
- local nomsu = NomsuCode(tree.source)
- for i, bit in ipairs(tree) do
- if type(bit) == 'string' then
- local bit_lines = files.get_lines(bit)
- for j, line in ipairs(bit_lines) do
- if j > 1 then
- nomsu:append("\n")
- end
- line = gsub(line, "\\", "\\\\")
- if #line > 1.25 * MAX_LINE then
- local remainder = line
- while #remainder > 0 do
- local split = find(remainder, " ", MAX_LINE, true)
- if split then
- local chunk
- chunk, remainder = sub(remainder, 1, split), sub(remainder, split + 1, -1)
- nomsu:append(chunk)
- elseif #remainder > 1.75 * MAX_LINE then
- split = math.floor(1.5 * MAX_LINE)
- local chunk
- chunk, remainder = sub(remainder, 1, split), sub(remainder, split + 1, -1)
- nomsu:append(chunk)
- else
- nomsu:append(remainder)
- break
- end
- if #remainder > 0 then
- nomsu:append("\\\n..")
- end
+ line = gsub(line, "\\", "\\\\")
+ if #line > 1.25 * MAX_LINE then
+ local remainder = line
+ while #remainder > 0 do
+ local split = find(remainder, " ", MAX_LINE, true)
+ if split then
+ local chunk
+ chunk, remainder = sub(remainder, 1, split), sub(remainder, split + 1, -1)
+ nomsu:append(chunk)
+ elseif #remainder > 1.75 * MAX_LINE then
+ split = math.floor(1.5 * MAX_LINE)
+ local chunk
+ chunk, remainder = sub(remainder, 1, split), sub(remainder, split + 1, -1)
+ nomsu:append(chunk)
+ else
+ nomsu:append(remainder)
+ break
+ end
+ if #remainder > 0 then
+ nomsu:append("\\\n..")
end
- else
- nomsu:append(line)
end
+ else
+ nomsu:append(line)
end
- elseif bit.type == "Text" then
- nomsu:append(make_text(bit))
- else
- local interp_nomsu = recurse(bit, {
- inline = true
- })
- if interp_nomsu then
- if bit.type ~= "Var" and bit.type ~= "List" and bit.type ~= "Dict" then
- interp_nomsu:parenthesize()
- elseif bit.type == "Var" and type(tree[i + 1]) == 'string' and not match(tree[i + 1], "^[ \n\t,.:;#(){}[%]]") then
+ end
+ elseif bit.type == "Text" then
+ nomsu:append(make_text(bit))
+ else
+ local interp_nomsu = self:tree_to_inline_nomsu(bit)
+ if nomsu:trailing_line_len() + #tostring(interp_nomsu) <= MAX_LINE then
+ local _exp_1 = bit.type
+ if "Var" == _exp_1 then
+ if type(tree[i + 1]) == 'string' and not match(tree[i + 1], "^[ \n\t,.:;#(){}[%]]") then
interp_nomsu:parenthesize()
end
+ elseif "List" == _exp_1 or "Dict" == _exp_1 then
nomsu:append("\\", interp_nomsu)
else
- interp_nomsu = assert(recurse(bit))
- if not (interp_nomsu) then
- return nil
- end
- if bit.type ~= "List" and bit.type ~= "Dict" and bit.type ~= "Text" and bit.type ~= "Block" then
- nomsu:append("\\\n(..) ", interp_nomsu)
- else
- nomsu:append("\\", interp_nomsu)
- end
- if i < #tree then
- nomsu:append("\n..")
- end
+ nomsu:append("\\(", interp_nomsu, ")")
+ end
+ else
+ interp_nomsu = recurse(bit)
+ if bit.type ~= "List" and bit.type ~= "Dict" and bit.type ~= "Text" and bit.type ~= "Block" then
+ nomsu:append("\\(..)\n ", interp_nomsu)
+ else
+ nomsu:append("\\", interp_nomsu)
+ end
+ if i < #tree then
+ nomsu:append("\n..")
end
end
end
- return nomsu
end
- return NomsuCode(tree.source, '".."\n ', make_text(tree))
+ return nomsu
end
+ return NomsuCode(tree.source, '".."\n ', make_text(tree))
elseif "List" == _exp_0 then
- if options.inline then
- local nomsu = NomsuCode(tree.source, "[")
- for i, item in ipairs(tree) do
- if i > 1 then
- nomsu:append(", ")
- end
- nomsu:append(assert(recurse(item, {
- inline = true
- })))
- end
- nomsu:append("]")
- return nomsu
- else
- local inline_version = recurse(tree, {
- inline = true
- })
- if inline_version and #tostring(inline_version) <= MAX_LINE then
- return inline_version
+ local inline_version = self:tree_to_inline_nomsu(tree)
+ if inline_version and #tostring(inline_version) <= MAX_LINE then
+ return inline_version
+ end
+ assert(#tree > 0)
+ local nomsu = NomsuCode(tree.source, pop_comments(tree[1].source.start))
+ for i, item in ipairs(tree) do
+ local item_nomsu = self:tree_to_inline_nomsu(item)
+ if item.type == "Block" then
+ item_nomsu:parenthesize()
end
- assert(#tree > 0)
- local nomsu = NomsuCode(tree.source, pop_comments(tree[1].source.start))
- for i, item in ipairs(tree) do
- local item_nomsu = assert(recurse(item, {
- inline = true
- }))
- if item.type == "Block" then
- item_nomsu:parenthesize()
+ if nomsu:trailing_line_len() + #tostring(item_nomsu) <= MAX_LINE then
+ if nomsu:trailing_line_len() > 0 then
+ nomsu:append(", ")
end
- if nomsu:trailing_line_len() + #tostring(item_nomsu) <= MAX_LINE then
- if nomsu:trailing_line_len() > 0 then
- nomsu:append(", ")
- end
+ nomsu:append(item_nomsu)
+ else
+ item_nomsu = recurse(item)
+ local _exp_1 = item.type
+ if "List" == _exp_1 or "Dict" == _exp_1 or "Text" == _exp_1 or "Block" == _exp_1 or "EscapedNomsu" == _exp_1 then
nomsu:append(item_nomsu)
else
- if #tostring(item_nomsu) > MAX_LINE then
- item_nomsu = recurse(item)
- local _exp_1 = item.type
- if "List" == _exp_1 or "Dict" == _exp_1 or "Text" == _exp_1 or "Block" == _exp_1 then
- nomsu:append(item_nomsu)
- else
- nomsu:append("(..)\n ", item_nomsu)
- end
- if i < #tree then
- nomsu:append("\n")
- end
- else
- if nomsu:trailing_line_len() > 0 then
- nomsu:append('\n')
- end
- nomsu:append(pop_comments(item.source.start), item_nomsu)
- end
+ nomsu:append("(..)\n ", item_nomsu)
+ end
+ if i < #tree then
+ nomsu:append("\n")
end
end
- nomsu:append(pop_comments(tree.source.stop, '\n'))
- return NomsuCode(tree.source, "[..]\n ", nomsu)
end
+ nomsu:append(pop_comments(tree.source.stop, '\n'))
+ return NomsuCode(tree.source, "[..]\n ", nomsu)
elseif "Dict" == _exp_0 then
- if options.inline then
- local nomsu = NomsuCode(tree.source, "{")
- for i, entry in ipairs(tree) do
- if i > 1 then
- nomsu:append(", ")
- end
- nomsu:append(assert(recurse(entry, {
- inline = true
- })))
- end
- nomsu:append("}")
- return nomsu
- else
- local inline_version = recurse(tree, {
- inline = true
- })
- if inline_version and #tostring(inline_version) <= MAX_LINE then
- return inline_version
+ local inline_version = self:tree_to_inline_nomsu(tree)
+ if inline_version and #tostring(inline_version) <= MAX_LINE then
+ return inline_version
+ end
+ assert(#tree > 0)
+ local nomsu = NomsuCode(tree.source, pop_comments(tree[1].source.start))
+ for i, item in ipairs(tree) do
+ local item_nomsu = self:tree_to_inline_nomsu(item)
+ if item.type == "Block" then
+ item_nomsu:parenthesize()
end
- assert(#tree > 0)
- local nomsu = NomsuCode(tree.source, pop_comments(tree[1].source.start))
- for i, item in ipairs(tree) do
- local item_nomsu = assert(recurse(item, {
- inline = true
- }))
- if item.type == "Block" then
- item_nomsu:parenthesize()
+ if nomsu:trailing_line_len() + #tostring(item_nomsu) <= MAX_LINE then
+ if nomsu:trailing_line_len() > 0 then
+ nomsu:append(", ")
end
- if nomsu:trailing_line_len() + #tostring(item_nomsu) <= MAX_LINE then
- if nomsu:trailing_line_len() > 0 then
- nomsu:append(", ")
- end
+ nomsu:append(item_nomsu)
+ else
+ item_nomsu = recurse(item)
+ local _exp_1 = item.type
+ if "List" == _exp_1 or "Dict" == _exp_1 or "Text" == _exp_1 or "Block" == _exp_1 or "EscapedNomsu" == _exp_1 then
nomsu:append(item_nomsu)
else
- if #tostring(item_nomsu) > MAX_LINE then
- item_nomsu = recurse(item)
- local _exp_1 = item.type
- if "List" == _exp_1 or "Dict" == _exp_1 or "Text" == _exp_1 or "Block" == _exp_1 then
- nomsu:append(item_nomsu)
- else
- nomsu:append("(..)\n ", item_nomsu)
- end
- if i < #tree then
- nomsu:append("\n")
- end
- else
- if nomsu:trailing_line_len() > 0 then
- nomsu:append('\n')
- end
- nomsu:append(pop_comments(item.source.start), item_nomsu)
- end
+ nomsu:append("(..)\n ", item_nomsu)
+ end
+ if i < #tree then
+ nomsu:append("\n")
end
end
- nomsu:append(pop_comments(tree.source.stop, '\n'))
- return NomsuCode(tree.source, "{..}\n ", nomsu)
end
+ nomsu:append(pop_comments(tree.source.stop, '\n'))
+ return NomsuCode(tree.source, "{..}\n ", nomsu)
elseif "DictEntry" == _exp_0 then
+ local inline_version = self:tree_to_inline_nomsu(tree)
+ if #tostring(inline_version) <= MAX_LINE then
+ return inline_version
+ end
local key, value = tree[1], tree[2]
local key_nomsu
if key.type == "Text" and #key == 1 and Parser.is_identifier(key[1]) then
key_nomsu = NomsuCode(key.source, key[1])
else
- key_nomsu = assert(recurse(key, {
- inline = true
- }))
+ key_nomsu = self:tree_to_inline_nomsu(key)
end
if key.type == "Action" or key.type == "Block" then
key_nomsu:parenthesize()
end
- local value_nomsu
- if value then
- value_nomsu = assert(recurse(value, {
- inline = true
- }))
- else
- value_nomsu = NomsuCode(tree.source, "")
- end
- assert(value.type ~= "Block", "Didn't expect to find a Block as a value in a dict")
- if value.type == "Block" then
- value_nomsu:parenthesize()
- end
- if options.inline or #tostring(key_nomsu) + 2 + #tostring(value_nomsu) <= MAX_LINE then
- return NomsuCode(tree.source, key_nomsu, ": ", value_nomsu)
- end
- value_nomsu = recurse(value)
- if value.type == "List" or value.type == "Dict" or value.type == "Text" then
+ local value_nomsu = recurse(value)
+ if value.type == "List" or value.type == "Dict" or value.type == "Text" or value.type == "Block" then
return NomsuCode(tree.source, key_nomsu, ": ", value_nomsu)
else
return NomsuCode(tree.source, key_nomsu, ": (..)\n ", value_nomsu)
end
- elseif "IndexChain" == _exp_0 then
- local nomsu = NomsuCode(tree.source)
- for i, bit in ipairs(tree) do
- if i > 1 then
- nomsu:append(".")
- end
- local bit_nomsu
- if bit.type == "Text" and #bit == 1 and type(bit[1]) == 'string' and bit[1]:match("[_a-zA-Z][_a-zA-Z0-9]*") then
- bit_nomsu = bit[1]
- else
- bit_nomsu = assert(recurse(bit, {
- inline = true
- }))
- end
- local _exp_1 = bit.type
- if "Action" == _exp_1 or "Block" == _exp_1 or "IndexChain" == _exp_1 then
- bit_nomsu:parenthesize()
- elseif "Number" == _exp_1 then
- if i < #tree then
- bit_nomsu:parenthesize()
- end
- end
- nomsu:append(bit_nomsu)
- end
- return nomsu
- elseif "Number" == _exp_0 then
- return NomsuCode(tree.source, tostring(tree[1]))
- elseif "Var" == _exp_0 then
- return NomsuCode(tree.source, "%", tree[1])
+ elseif "IndexChain" == _exp_0 or "Number" == _exp_0 or "Var" == _exp_0 then
+ return self:tree_to_inline_nomsu(tree)
else
return error("Unknown type: " .. tostring(tree.type))
end
diff --git a/nomsu_compiler.moon b/nomsu_compiler.moon
index c92b996..1c9fbca 100644
--- a/nomsu_compiler.moon
+++ b/nomsu_compiler.moon
@@ -484,7 +484,114 @@ with NomsuCompiler
else
error("Unknown type: #{tree.type}")
- MIN_COLON_LEN = 20 -- For beautification purposes, don't bother using colon syntax for short bits
+ .tree_to_inline_nomsu = (tree, parenthesize_blocks=false)=>
+ switch tree.type
+ when "FileChunks"
+ error("Cannot inline a FileChunks")
+
+ when "Action"
+ nomsu = NomsuCode(tree.source)
+ for i,bit in ipairs tree
+ if type(bit) == "string"
+ clump_words = (type(tree[i-1]) == 'string' and Parser.is_operator(bit) != Parser.is_operator(tree[i-1]))
+ nomsu\append " " if i > 1 and not clump_words
+ nomsu\append bit
+ else
+ arg_nomsu = @tree_to_inline_nomsu(bit, parenthesize_blocks or (i == 1 or i < #tree))
+ nomsu\append " " unless tostring(arg_nomsu)\match("^:") or i == 1
+ arg_nomsu\parenthesize! if bit.type == "Action"
+ nomsu\append arg_nomsu
+ return nomsu
+
+ when "EscapedNomsu"
+ inner_nomsu = @tree_to_inline_nomsu(tree[1])
+ if tree[1].type == "List" or tree[1].type == "Dict" or tree[1].type == "Var"
+ return NomsuCode(tree.source, "\\", inner_nomsu)
+ else
+ return NomsuCode(tree.source, "\\(", inner_nomsu, ")")
+
+ when "Block"
+ nomsu = NomsuCode(tree.source, ":")
+ for i,line in ipairs tree
+ nomsu\append(i == 1 and " " or "; ")
+ nomsu\append @tree_to_inline_nomsu(line, i == 1 or i < #tree)
+ nomsu\parenthesize! if #tree > 1 or parenthesize_blocks
+ return nomsu
+
+ when "Text"
+ make_text = (tree)->
+ nomsu = NomsuCode(tree.source)
+ for i, bit in ipairs tree
+ if type(bit) == 'string'
+ bit = Parser.inline_escape(bit)
+ nomsu\append bit
+ elseif bit.type == "Text"
+ nomsu\append(make_text(bit))
+ else
+ interp_nomsu = @tree_to_inline_nomsu(bit)
+ if bit.type != "Var" and bit.type != "List" and bit.type != "Dict"
+ interp_nomsu\parenthesize!
+ elseif bit.type == "Var" and type(tree[i+1]) == 'string' and not match(tree[i+1], "^[ \n\t,.:;#(){}[%]]")
+ interp_nomsu\parenthesize!
+ nomsu\append "\\", interp_nomsu
+ return nomsu
+ return NomsuCode(tree.source, '"', make_text(tree), '"')
+
+ when "List"
+ nomsu = NomsuCode(tree.source, "[")
+ for i, item in ipairs tree
+ nomsu\append ", " if i > 1
+ nomsu\append @tree_to_inline_nomsu(item)
+ nomsu\append "]"
+ return nomsu
+
+ when "Dict"
+ nomsu = NomsuCode(tree.source, "{")
+ for i, entry in ipairs tree
+ nomsu\append ", " if i > 1
+ nomsu\append @tree_to_inline_nomsu(entry)
+ nomsu\append "}"
+ return nomsu
+
+ when "DictEntry"
+ key, value = tree[1], tree[2]
+ key_nomsu = if key.type == "Text" and #key == 1 and Parser.is_identifier(key[1])
+ NomsuCode(key.source, key[1])
+ else @tree_to_inline_nomsu(key)
+ key_nomsu\parenthesize! if key.type == "Action" or key.type == "Block"
+ value_nomsu = if value
+ @tree_to_inline_nomsu(value)
+ else NomsuCode(tree.source, "")
+ assert(value.type != "Block", "Didn't expect to find a Block as a value in a dict")
+ value_nomsu\parenthesize! if value.type == "Block"
+ return NomsuCode tree.source, key_nomsu, ": ", value_nomsu
+
+ when "IndexChain"
+ nomsu = NomsuCode(tree.source)
+ for i, bit in ipairs tree
+ nomsu\append "." if i > 1
+ local bit_nomsu
+ bit_nomsu = if bit.type == "Text" and #bit == 1 and type(bit[1]) == 'string' and Parser.is_identifier(bit[1])
+ bit[1]
+ else @tree_to_inline_nomsu(bit)
+ switch bit.type
+ when "Action", "Block", "IndexChain"
+ bit_nomsu\parenthesize!
+ when "Number"
+ if i < #tree
+ bit_nomsu\parenthesize!
+ nomsu\append bit_nomsu
+ return nomsu
+
+ when "Number"
+ return NomsuCode(tree.source, tostring(tree[1]))
+
+ when "Var"
+ return NomsuCode(tree.source, "%", tree[1])
+
+ else
+ error("Unknown type: #{tree.type}")
+
.tree_to_nomsu = (tree, options)=>
options or= {}
options.consumed_comments or= {}
@@ -509,12 +616,10 @@ with NomsuCompiler
recurse = (t, opts)->
opts or= {}
opts.consumed_comments = options.consumed_comments
- opts.inside_multiblock or= options.inside_multiblock
return @tree_to_nomsu(t, opts)
switch tree.type
when "FileChunks"
- error("Cannot inline a FileChunks") if options.inline
nomsu = NomsuCode(tree.source, pop_comments(tree.source.start))
for i, chunk in ipairs tree
nomsu\append "\n\n#{("~")\rep(80)}\n\n" if i > 1
@@ -524,72 +629,53 @@ with NomsuCompiler
return nomsu
when "Action"
- if options.inline
- nomsu = NomsuCode(tree.source)
- for i,bit in ipairs tree
- if type(bit) == "string"
- nomsu\append " " if i > 1 and not (type(tree[i-1]) == 'string' and Parser.is_operator(bit) != Parser.is_operator(tree[i-1]))
- nomsu\append bit
- else
- arg_nomsu = recurse(bit,inline:true)
- return nil unless arg_nomsu
+ pos = tree.source.start
+ nomsu = NomsuCode(tree.source, pop_comments(pos))
+ next_space = ""
+ for i,bit in ipairs tree
+ if match(next_space, '\n')
+ nomsu\append pop_comments(pos, '\n')
+ if type(bit) == "string"
+ if next_space == ' ' and (type(tree[i-1]) == 'string' and Parser.is_operator(bit) != Parser.is_operator(tree[i-1]))
+ next_space = ''
+ nomsu\append next_space, bit
+ next_space = " "
+ else
+ arg_nomsu = if bit.type == "Block" and #bit > 1 then nil
+ else @tree_to_inline_nomsu(bit)
+ if bit.type == "Text" and tostring(arg_nomsu) != '"\\n"' and tostring(arg_nomsu)\match("\\n")
+ arg_nomsu = nil -- Force long text for multi-line text
+ next_space = match(next_space, "[^ ]*") if bit.type == "Block"
+ nomsu\append next_space
+ if arg_nomsu and nomsu\trailing_line_len! + #tostring(arg_nomsu) < MAX_LINE
if bit.type == "Block"
- if i == 1 or i < #tree or options.inside_multiblock
- nomsu\append " " if i > 1
- arg_nomsu\parenthesize!
nomsu\append arg_nomsu
+ next_space = "\n.."
else
- nomsu\append " " if i > 1
arg_nomsu\parenthesize! if bit.type == "Action"
nomsu\append arg_nomsu
- return nomsu
- else
- pos = tree.source.start
- nomsu = NomsuCode(tree.source, pop_comments(pos))
- next_space = ""
- for i,bit in ipairs tree
- if match(next_space, '\n')
- nomsu\append pop_comments(pos, '\n')
- if type(bit) == "string"
- if next_space == ' ' and (type(tree[i-1]) == 'string' and Parser.is_operator(bit) != Parser.is_operator(tree[i-1]))
- next_space = ''
- nomsu\append next_space, bit
- next_space = " "
+ next_space = " "
else
- arg_nomsu = if bit.type == "Block" and #bit > 1 then nil
- else assert recurse(bit,inline:true)
- if tostring(arg_nomsu) != '"\\n"' and tostring(arg_nomsu)\match("\\n")
- arg_nomsu = nil -- Force long text for multi-line text
- next_space = match(next_space, "[^ ]*") if bit.type == "Block"
- nomsu\append next_space
- if arg_nomsu and nomsu\trailing_line_len! + #tostring(arg_nomsu) < MAX_LINE
- if bit.type == "Block"
+ arg_nomsu = assert recurse(bit)
+ -- These types carry their own indentation
+ switch bit.type
+ when "List", "Dict", "Text", "Block", "EscapedNomsu"
nomsu\append arg_nomsu
- next_space = "\n.."
else
- arg_nomsu\parenthesize! if bit.type == "Action"
- nomsu\append arg_nomsu
- next_space = " "
- else
- arg_nomsu = assert recurse(bit)
- -- These types carry their own indentation
- if bit.type != "List" and bit.type != "Dict" and bit.type != "Text" and bit.type != "Block"
nomsu\append NomsuCode(bit.source, "(..)\n ", pop_comments(bit.source.start), arg_nomsu)
- else
- nomsu\append arg_nomsu
- next_space = "\n.."
- pos = bit.source.stop
-
- if next_space == " " and nomsu\trailing_line_len! > MAX_LINE
next_space = "\n.."
- nomsu\append pop_comments(pos, '\n')
- return nomsu
+ pos = bit.source.stop
+
+ if next_space == " " and nomsu\trailing_line_len! > MAX_LINE
+ next_space = "\n.."
+ nomsu\append pop_comments(pos, '\n')
+ return nomsu
when "EscapedNomsu"
- nomsu = NomsuCode(tree.source, "\\(", assert(recurse(tree[1], inline:true)), ")")
- if options.inline or #tostring(nomsu) <= MAX_LINE
- return nomsu
- nomsu = assert recurse(tree[1])
+ inline_nomsu = @tree_to_inline_nomsu tree
+ if #tostring(inline_nomsu) <= MAX_LINE
+ return inline_nomsu
+ nomsu = recurse(tree[1])
switch tree[1].type
when "List", "Dict", "Text", "Block"
return NomsuCode tree.source, "\\", nomsu
@@ -597,208 +683,133 @@ with NomsuCompiler
return NomsuCode tree.source, "\\(..)\n ", pop_comments(tree.source.start), nomsu
when "Block"
- if options.inline
- nomsu = NomsuCode(tree.source, ":")
- for i,line in ipairs tree
- nomsu\append(i == 1 and " " or "; ")
- nomsu\append assert(recurse(line, inline:true, inside_multiblock:true))
- return nomsu
nomsu = NomsuCode(tree.source, pop_comments(tree.source.start))
for i, line in ipairs tree
nomsu\append pop_comments(line.source.start, '\n')
- line = assert(recurse(line), "Could not convert line to nomsu")
- nomsu\append line
+ line_nomsu = recurse(line)
+ nomsu\append line_nomsu
if i < #tree
- nomsu\append "\n"
- if match(tostring(line), "\n")
- nomsu\append "\n"
+ nomsu\append(line_nomsu\is_multiline! and "\n\n" or "\n")
nomsu\append pop_comments(tree.source.stop, '\n')
return options.top and nomsu or NomsuCode(tree.source, ":\n ", nomsu)
when "Text"
- if options.inline
- make_text = (tree)->
- nomsu = NomsuCode(tree.source)
- for i, bit in ipairs tree
- if type(bit) == 'string'
- -- TODO: unescape better?
- bit = (gsub(gsub(gsub(bit,"\\","\\\\"),"\n","\\n"),'"','\\"'))
- bit = gsub(bit, "%G", ((c)-> c == ' ' and c or "\\#{c\byte!}"))
- nomsu\append bit
- elseif bit.type == "Text"
- nomsu\append(make_text(bit))
- else
- interp_nomsu = assert recurse(bit, inline:true)
- if bit.type != "Var" and bit.type != "List" and bit.type != "Dict"
- interp_nomsu\parenthesize!
- elseif bit.type == "Var" and type(tree[i+1]) == 'string' and not match(tree[i+1], "^[ \n\t,.:;#(){}[%]]")
- interp_nomsu\parenthesize!
- nomsu\append "\\", interp_nomsu
- return nomsu
- return NomsuCode(tree.source, '"', make_text(tree), '"')
- else
- inline_version = recurse(tree, inline:true)
- if inline_version and #tostring(inline_version) <= MAX_LINE
- return inline_version
- make_text = (tree)->
- nomsu = NomsuCode(tree.source)
- for i, bit in ipairs tree
- if type(bit) == 'string'
- bit_lines = files.get_lines(bit)
- for j, line in ipairs bit_lines
- if j > 1 then nomsu\append "\n"
- line = gsub(line, "\\", "\\\\")
- if #line > 1.25*MAX_LINE
- remainder = line
- while #remainder > 0
- split = find(remainder, " ", MAX_LINE, true)
- if split
- chunk, remainder = sub(remainder, 1, split), sub(remainder, split+1, -1)
- nomsu\append chunk
- elseif #remainder > 1.75*MAX_LINE
- split = math.floor(1.5*MAX_LINE)
- chunk, remainder = sub(remainder, 1, split), sub(remainder, split+1, -1)
- nomsu\append chunk
- else
- nomsu\append remainder
- break
- if #remainder > 0 then nomsu\append "\\\n.."
+ inline_version = @tree_to_inline_nomsu(tree)
+ if inline_version and #tostring(inline_version) <= MAX_LINE
+ return inline_version
+ make_text = (tree)->
+ nomsu = NomsuCode(tree.source)
+ for i, bit in ipairs tree
+ if type(bit) == 'string'
+ bit = Parser.escape(bit)
+ bit_lines = files.get_lines(bit)
+ for j, line in ipairs bit_lines
+ if j > 1 then nomsu\append "\n"
+ line = gsub(line, "\\", "\\\\")
+ if #line > 1.25*MAX_LINE
+ remainder = line
+ while #remainder > 0
+ split = find(remainder, " ", MAX_LINE, true)
+ if split
+ chunk, remainder = sub(remainder, 1, split), sub(remainder, split+1, -1)
+ nomsu\append chunk
+ elseif #remainder > 1.75*MAX_LINE
+ split = math.floor(1.5*MAX_LINE)
+ chunk, remainder = sub(remainder, 1, split), sub(remainder, split+1, -1)
+ nomsu\append chunk
+ else
+ nomsu\append remainder
+ break
+ if #remainder > 0 then nomsu\append "\\\n.."
+ else
+ nomsu\append line
+ elseif bit.type == "Text"
+ nomsu\append make_text(bit)
+ else
+ interp_nomsu = @tree_to_inline_nomsu(bit)
+ if nomsu\trailing_line_len! + #tostring(interp_nomsu) <= MAX_LINE
+ switch bit.type
+ when "Var"
+ if type(tree[i+1]) == 'string' and not match(tree[i+1], "^[ \n\t,.:;#(){}[%]]")
+ interp_nomsu\parenthesize!
+ when "List", "Dict"
+ nomsu\append "\\", interp_nomsu
else
- nomsu\append line
- elseif bit.type == "Text"
- nomsu\append make_text(bit)
+ nomsu\append "\\(", interp_nomsu, ")"
else
- interp_nomsu = recurse(bit, inline:true)
- if interp_nomsu
- if bit.type != "Var" and bit.type != "List" and bit.type != "Dict"
- interp_nomsu\parenthesize!
- elseif bit.type == "Var" and type(tree[i+1]) == 'string' and not match(tree[i+1], "^[ \n\t,.:;#(){}[%]]")
- interp_nomsu\parenthesize!
- nomsu\append "\\", interp_nomsu
+ interp_nomsu = recurse(bit)
+ if bit.type != "List" and bit.type != "Dict" and bit.type != "Text" and bit.type != "Block"
+ nomsu\append "\\(..)\n ", interp_nomsu
else
- interp_nomsu = assert(recurse(bit))
- return nil unless interp_nomsu
- if bit.type != "List" and bit.type != "Dict" and bit.type != "Text" and bit.type != "Block"
- nomsu\append "\\\n(..) ", interp_nomsu
- else
- nomsu\append "\\", interp_nomsu
- if i < #tree
- nomsu\append "\n.."
- return nomsu
- return NomsuCode(tree.source, '".."\n ', make_text(tree))
+ nomsu\append "\\", interp_nomsu
+ if i < #tree
+ nomsu\append "\n.."
+ return nomsu
+ return NomsuCode(tree.source, '".."\n ', make_text(tree))
when "List"
- if options.inline
- nomsu = NomsuCode(tree.source, "[")
- for i, item in ipairs tree
- nomsu\append ", " if i > 1
- nomsu\append assert(recurse(item, inline:true))
- nomsu\append "]"
- return nomsu
- else
- inline_version = recurse(tree, inline:true)
- if inline_version and #tostring(inline_version) <= MAX_LINE
- return inline_version
- assert #tree > 0
- nomsu = NomsuCode(tree.source, pop_comments(tree[1].source.start))
- for i, item in ipairs tree
- item_nomsu = assert recurse(item, inline:true)
- item_nomsu\parenthesize! if item.type == "Block"
- if nomsu\trailing_line_len! + #tostring(item_nomsu) <= MAX_LINE
- nomsu\append ", " if nomsu\trailing_line_len! > 0
- nomsu\append item_nomsu
- else
- if #tostring(item_nomsu) > MAX_LINE
- item_nomsu = recurse(item)
- switch item.type
- when "List", "Dict", "Text", "Block"
- nomsu\append item_nomsu
- else
- nomsu\append "(..)\n ", item_nomsu
- nomsu\append "\n" if i < #tree
+ inline_version = @tree_to_inline_nomsu tree
+ if inline_version and #tostring(inline_version) <= MAX_LINE
+ return inline_version
+ assert #tree > 0
+ nomsu = NomsuCode(tree.source, pop_comments(tree[1].source.start))
+ for i, item in ipairs tree
+ item_nomsu = @tree_to_inline_nomsu(item)
+ item_nomsu\parenthesize! if item.type == "Block"
+ if nomsu\trailing_line_len! + #tostring(item_nomsu) <= MAX_LINE
+ nomsu\append ", " if nomsu\trailing_line_len! > 0
+ nomsu\append item_nomsu
+ else
+ item_nomsu = recurse(item)
+ switch item.type
+ when "List", "Dict", "Text", "Block", "EscapedNomsu"
+ nomsu\append item_nomsu
else
- nomsu\append '\n' if nomsu\trailing_line_len! > 0
- nomsu\append pop_comments(item.source.start), item_nomsu
- nomsu\append pop_comments(tree.source.stop, '\n')
- return NomsuCode(tree.source, "[..]\n ", nomsu)
+ nomsu\append "(..)\n ", item_nomsu
+ nomsu\append "\n" if i < #tree
+ nomsu\append pop_comments(tree.source.stop, '\n')
+ return NomsuCode(tree.source, "[..]\n ", nomsu)
when "Dict"
- if options.inline
- nomsu = NomsuCode(tree.source, "{")
- for i, entry in ipairs tree
- nomsu\append ", " if i > 1
- nomsu\append assert(recurse(entry, inline:true))
- nomsu\append "}"
- return nomsu
- else
- inline_version = recurse(tree, inline:true)
- if inline_version and #tostring(inline_version) <= MAX_LINE
- return inline_version
- assert #tree > 0
- nomsu = NomsuCode(tree.source, pop_comments(tree[1].source.start))
- for i, item in ipairs tree
- item_nomsu = assert recurse(item, inline:true)
- item_nomsu\parenthesize! if item.type == "Block"
- if nomsu\trailing_line_len! + #tostring(item_nomsu) <= MAX_LINE
- nomsu\append ", " if nomsu\trailing_line_len! > 0
- nomsu\append item_nomsu
- else
- if #tostring(item_nomsu) > MAX_LINE
- item_nomsu = recurse(item)
- switch item.type
- when "List", "Dict", "Text", "Block"
- nomsu\append item_nomsu
- else
- nomsu\append "(..)\n ", item_nomsu
- nomsu\append "\n" if i < #tree
+ inline_version = @tree_to_inline_nomsu tree
+ if inline_version and #tostring(inline_version) <= MAX_LINE
+ return inline_version
+ assert #tree > 0
+ nomsu = NomsuCode(tree.source, pop_comments(tree[1].source.start))
+ for i, item in ipairs tree
+ item_nomsu = @tree_to_inline_nomsu(item)
+ item_nomsu\parenthesize! if item.type == "Block"
+ if nomsu\trailing_line_len! + #tostring(item_nomsu) <= MAX_LINE
+ nomsu\append ", " if nomsu\trailing_line_len! > 0
+ nomsu\append item_nomsu
+ else
+ item_nomsu = recurse(item)
+ switch item.type
+ when "List", "Dict", "Text", "Block", "EscapedNomsu"
+ nomsu\append item_nomsu
else
- nomsu\append '\n' if nomsu\trailing_line_len! > 0
- nomsu\append pop_comments(item.source.start), item_nomsu
- nomsu\append pop_comments(tree.source.stop, '\n')
- return NomsuCode(tree.source, "{..}\n ", nomsu)
+ nomsu\append "(..)\n ", item_nomsu
+ nomsu\append "\n" if i < #tree
+ nomsu\append pop_comments(tree.source.stop, '\n')
+ return NomsuCode(tree.source, "{..}\n ", nomsu)
when "DictEntry"
+ inline_version = @tree_to_inline_nomsu tree
+ if #tostring(inline_version) <= MAX_LINE
+ return inline_version
key, value = tree[1], tree[2]
key_nomsu = if key.type == "Text" and #key == 1 and Parser.is_identifier(key[1])
NomsuCode(key.source, key[1])
- else assert recurse(key, inline:true)
+ else @tree_to_inline_nomsu(key)
key_nomsu\parenthesize! if key.type == "Action" or key.type == "Block"
- value_nomsu = if value
- assert recurse(value, inline:true)
- else NomsuCode(tree.source, "")
- assert(value.type != "Block", "Didn't expect to find a Block as a value in a dict")
- value_nomsu\parenthesize! if value.type == "Block"
- if options.inline or #tostring(key_nomsu) + 2 + #tostring(value_nomsu) <= MAX_LINE
- return NomsuCode tree.source, key_nomsu, ": ", value_nomsu
value_nomsu = recurse(value)
- if value.type == "List" or value.type == "Dict" or value.type == "Text"
+ if value.type == "List" or value.type == "Dict" or value.type == "Text" or value.type == "Block"
return NomsuCode tree.source, key_nomsu, ": ", value_nomsu
else
return NomsuCode tree.source, key_nomsu, ": (..)\n ", value_nomsu
- when "IndexChain"
- nomsu = NomsuCode(tree.source)
- for i, bit in ipairs tree
- nomsu\append "." if i > 1
- local bit_nomsu
- bit_nomsu = if bit.type == "Text" and #bit == 1 and type(bit[1]) == 'string' and bit[1]\match("[_a-zA-Z][_a-zA-Z0-9]*")
- -- TODO: support arbitrary words here, including operators and unicode
- bit[1]
- else assert recurse(bit, inline:true)
- switch bit.type
- when "Action", "Block", "IndexChain"
- bit_nomsu\parenthesize!
- when "Number"
- if i < #tree
- bit_nomsu\parenthesize!
- nomsu\append bit_nomsu
- return nomsu
-
- when "Number"
- return NomsuCode(tree.source, tostring(tree[1]))
-
- when "Var"
- return NomsuCode(tree.source, "%", tree[1])
+ when "IndexChain", "Number", "Var"
+ return @tree_to_inline_nomsu tree
else
error("Unknown type: #{tree.type}")
diff --git a/parser.lua b/parser.lua
index c3478dc..b5fb258 100644
--- a/parser.lua
+++ b/parser.lua
@@ -234,4 +234,22 @@ end
Parser.is_identifier = function(s)
return not not (NOMSU_DEFS.ident_char ^ 1 * -1):match(s)
end
+local inline_escaper = re.compile("{~ (%utf8_char / ('\\' -> '\\\\') / [ -~] / ('\n' -> '\\n') / ('\t' -> '\\t') / ('\b' -> '\\b') / ('\a' -> '\\a') / ('\v' -> '\\v') / ('\f' -> '\\f') / ('\r' -> '\\r') / ('\"' -> '\\\"') / (. -> escape))* ~}", {
+ utf8_char = NOMSU_DEFS.utf8_char,
+ escape = (function(self)
+ return ("\\%03d"):format(self:byte())
+ end)
+})
+Parser.inline_escape = function(s)
+ return inline_escaper:match(s)
+end
+local escaper = re.compile("{~ (%utf8_char / ('\\' -> '\\\\') / [\n\r\t -~] / (. -> escape))* ~}", {
+ utf8_char = NOMSU_DEFS.utf8_char,
+ escape = (function(self)
+ return ("\\%03d"):format(self:byte())
+ end)
+})
+Parser.escape = function(s)
+ return escaper:match(s)
+end
return Parser
diff --git a/parser.moon b/parser.moon
index 993fd54..1998ae2 100644
--- a/parser.moon
+++ b/parser.moon
@@ -144,4 +144,11 @@ Parser.is_operator = (s)->
Parser.is_identifier = (s)->
return not not (NOMSU_DEFS.ident_char^1 * -1)\match(s)
+inline_escaper = re.compile "{~ (%utf8_char / ('\\' -> '\\\\') / [ -~] / ('\n' -> '\\n') / ('\t' -> '\\t') / ('\b' -> '\\b') / ('\a' -> '\\a') / ('\v' -> '\\v') / ('\f' -> '\\f') / ('\r' -> '\\r') / ('\"' -> '\\\"') / (. -> escape))* ~}", {utf8_char: NOMSU_DEFS.utf8_char, escape:(=> ("\\%03d")\format(@byte!))}
+Parser.inline_escape = (s)->
+ return inline_escaper\match(s)
+escaper = re.compile "{~ (%utf8_char / ('\\' -> '\\\\') / [\n\r\t -~] / (. -> escape))* ~}", {utf8_char: NOMSU_DEFS.utf8_char, escape:(=> ("\\%03d")\format(@byte!))}
+Parser.escape = (s)->
+ return escaper\match(s)
+
return Parser
diff --git a/tools/autoformat.nom b/tools/autoformat.nom
index 7126608..de25292 100755
--- a/tools/autoformat.nom
+++ b/tools/autoformat.nom
@@ -1,6 +1,17 @@
-#!/usr/bin/env nomsu -V2.3.4.3
+#!/usr/bin/env nomsu -V2.4.4.3
use "core"
use "lib/os.nom"
-for %path in (=lua "arg"):
+%args = (command line args)
+%inplace = (no)
+if (%args.1 is "-i"):
+ %inplace = (yes)
+ remove index 1 from %args
+
+for %path in %args:
for file %filename in %path:
- say ((parse (read file %filename) from %filename) as nomsu) \ No newline at end of file
+ %formatted = ".."
+ #!/usr/bin/env nomsu -V\(Nomsu version)
+ \((parse (read file %filename) from %filename) as nomsu)
+
+ if %inplace: write %formatted to file %filename
+ ..else: say %formatted \ No newline at end of file