aboutsummaryrefslogtreecommitdiff
path: root/nomsu_compiler.lua
diff options
context:
space:
mode:
Diffstat (limited to 'nomsu_compiler.lua')
-rw-r--r--nomsu_compiler.lua415
1 files changed, 199 insertions, 216 deletions
diff --git a/nomsu_compiler.lua b/nomsu_compiler.lua
index 10e93c9..1052c06 100644
--- a/nomsu_compiler.lua
+++ b/nomsu_compiler.lua
@@ -733,10 +733,26 @@ do
return error("Unknown type: " .. tostring(tree.type))
end
end
- NomsuCompiler.tree_to_inline_nomsu = function(self, tree, parenthesize_blocks)
+ NomsuCompiler.tree_to_inline_nomsu = function(self, tree, parenthesize_blocks, check, len)
if parenthesize_blocks == nil then
parenthesize_blocks = false
end
+ if check == nil then
+ check = nil
+ end
+ if len == nil then
+ len = 0
+ end
+ local recurse
+ recurse = function(tree, nomsu, parenthesize_blocks)
+ if nomsu == nil then
+ nomsu = nil
+ end
+ if parenthesize_blocks == nil then
+ parenthesize_blocks = false
+ end
+ return self:tree_to_inline_nomsu(tree, parenthesize_blocks, check, len + (nomsu and #tostring(nomsu) or 0))
+ end
local _exp_0 = tree.type
if "FileChunks" == _exp_0 then
return error("Cannot inline a FileChunks")
@@ -750,7 +766,7 @@ do
end
nomsu:append(bit)
else
- local arg_nomsu = self:tree_to_inline_nomsu(bit, parenthesize_blocks or (i == 1 or i < #tree))
+ local arg_nomsu = recurse(bit, nomsu, parenthesize_blocks or (i == 1 or i < #tree))
if not (tostring(arg_nomsu):match("^:") or i == 1) then
nomsu:append(" ")
end
@@ -759,20 +775,32 @@ do
end
nomsu:append(arg_nomsu)
end
+ if check then
+ check(len + #tostring(nomsu), tree)
+ 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, ")")
+ local inner_nomsu = recurse(tree[1])
+ if not (tree[1].type == "List" or tree[1].type == "Dict" or tree[1].type == "Var") then
+ inner_nomsu:parenthesize()
+ end
+ local nomsu = NomsuCode(tree.source, "\\", inner_nomsu)
+ if check then
+ check(len + #tostring(nomsu), tree)
end
+ return nomsu
elseif "Block" == _exp_0 then
+ if check then
+ check(len, tree)
+ end
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))
+ nomsu:append(recurse(line, nomsu, i == 1 or i < #tree))
+ if check then
+ check(len + #tostring(nomsu), tree)
+ end
end
if #tree > 1 or parenthesize_blocks then
nomsu:parenthesize()
@@ -789,7 +817,7 @@ do
elseif bit.type == "Text" then
nomsu:append(make_text(bit))
else
- local interp_nomsu = self:tree_to_inline_nomsu(bit)
+ local interp_nomsu = recurse(bit, nomsu)
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
@@ -797,6 +825,9 @@ do
end
nomsu:append("\\", interp_nomsu)
end
+ if check then
+ check(len + #tostring(nomsu), tree)
+ end
end
return nomsu
end
@@ -807,7 +838,10 @@ do
if i > 1 then
nomsu:append(", ")
end
- nomsu:append(self:tree_to_inline_nomsu(item))
+ nomsu:append(recurse(item, nomsu))
+ if check then
+ check(len + #tostring(nomsu), tree)
+ end
end
nomsu:append("]")
return nomsu
@@ -817,32 +851,37 @@ do
if i > 1 then
nomsu:append(", ")
end
- nomsu:append(self:tree_to_inline_nomsu(entry))
+ nomsu:append(recurse(entry, nomsu))
+ if check then
+ check(len + #tostring(nomsu), tree)
+ end
end
nomsu:append("}")
return nomsu
elseif "DictEntry" == _exp_0 then
local key, value = tree[1], tree[2]
- local key_nomsu
+ local nomsu
if key.type == "Text" and #key == 1 and Parser.is_identifier(key[1]) then
- key_nomsu = NomsuCode(key.source, key[1])
+ nomsu = NomsuCode(key.source, key[1])
else
- key_nomsu = self:tree_to_inline_nomsu(key)
+ nomsu = recurse(key)
end
if key.type == "Action" or key.type == "Block" then
- key_nomsu:parenthesize()
+ nomsu:parenthesize()
end
- local value_nomsu
+ assert(value.type ~= "Block", "Didn't expect to find a Block as a value in a dict")
+ nomsu:append(":")
if value then
- value_nomsu = self:tree_to_inline_nomsu(value)
- else
- value_nomsu = NomsuCode(tree.source, "")
+ local value_nomsu = recurse(value, nomsu)
+ if value.type == "Block" then
+ value_nomsu:parenthesize()
+ end
+ nomsu:append(value_nomsu)
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()
+ if check then
+ check(len + #tostring(nomsu), tree)
end
- return NomsuCode(tree.source, key_nomsu, ": ", value_nomsu)
+ return nomsu
elseif "IndexChain" == _exp_0 then
local nomsu = NomsuCode(tree.source)
for i, bit in ipairs(tree) do
@@ -853,17 +892,16 @@ do
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)
+ bit_nomsu = recurse(bit, nomsu)
end
- local _exp_1 = bit.type
- if "Action" == _exp_1 or "Block" == _exp_1 or "IndexChain" == _exp_1 then
+ assert(bit.type ~= "Block")
+ if bit.type == "Action" or bit.type == "IndexChain" or (bit.type == "Number" and i < #tree) then
bit_nomsu:parenthesize()
- elseif "Number" == _exp_1 then
- if i < #tree then
- bit_nomsu:parenthesize()
- end
end
nomsu:append(bit_nomsu)
+ if check then
+ check(len + #tostring(nomsu), tree)
+ end
end
return nomsu
elseif "Number" == _exp_0 then
@@ -874,23 +912,19 @@ do
return error("Unknown type: " .. tostring(tree.type))
end
end
- NomsuCompiler.tree_to_nomsu = function(self, tree, comments)
- if comments == nil then
- comments = nil
+ NomsuCompiler.tree_to_nomsu = function(self, tree, pop_comments)
+ if pop_comments == nil then
+ pop_comments = nil
end
- if not (comments) then
- local visited
- comments, visited = { }, { }
+ if not (pop_comments) then
+ local comment_set = { }
local find_comments
find_comments = function(t)
if t.comments and t.source.filename == tree.source.filename then
local _list_0 = t.comments
for _index_0 = 1, #_list_0 do
local c = _list_0[_index_0]
- if not (visited[c]) then
- insert(comments, c)
- visited[c] = true
- end
+ comment_set[c] = true
end
end
local _list_0 = t
@@ -902,44 +936,75 @@ do
end
end
find_comments(tree)
+ local comments
+ do
+ local _accum_0 = { }
+ local _len_0 = 1
+ for c in pairs(comment_set) do
+ _accum_0[_len_0] = c
+ _len_0 = _len_0 + 1
+ end
+ comments = _accum_0
+ end
table.sort(comments, function(a, b)
return (a.pos > b.pos)
end)
- end
- local pop_comments
- pop_comments = function(pos, prefix, suffix)
- if prefix == nil then
- prefix = ''
- end
- if suffix == nil then
- suffix = ''
- end
- local nomsu = NomsuCode(tree.source)
- for i = #comments, 1, -1 do
- if comments[i].pos > pos then
- break
+ pop_comments = function(pos, prefix, suffix)
+ if prefix == nil then
+ prefix = ''
end
- local comment
- comment, comments[i] = comments[i].comment, nil
- nomsu:append("#" .. (gsub(comment, "\n", "\n ")) .. "\n")
- if comment:match("^\n.") then
- nomsu:append("\n")
+ if suffix == nil then
+ suffix = ''
end
+ local nomsu = NomsuCode(tree.source)
+ for i = #comments, 1, -1 do
+ if comments[i].pos > pos then
+ break
+ end
+ local comment
+ comment, comments[i] = comments[i].comment, nil
+ nomsu:append("#" .. (gsub(comment, "\n", "\n ")) .. "\n")
+ if comment:match("^\n.") then
+ nomsu:append("\n")
+ end
+ end
+ if #nomsu.bits == 0 then
+ return ''
+ end
+ if not (prefix == '') then
+ nomsu:prepend(prefix)
+ end
+ if not (suffix == '') then
+ nomsu:append(suffix)
+ end
+ return nomsu
end
- if #nomsu.bits == 0 then
- return ''
+ end
+ local recurse
+ recurse = function(t, pos)
+ if pos == nil then
+ pos = 0
+ end
+ if type(pos) ~= 'number' then
+ pos = #tostring(pos):match("[ ]*([^\n]*)$")
+ end
+ local space = MAX_LINE - pos
+ local inline
+ for len, tree in coroutine.wrap(function()
+ inline = self:tree_to_inline_nomsu(t, false, coroutine.yield)
+ end) do
+ if len > MAX_LINE or (tree.type == "Block" and #tree > 1) then
+ break
+ end
end
- if not (prefix == '') then
- nomsu:prepend(prefix)
+ if inline and #tostring(inline) <= space then
+ return inline
end
- if not (suffix == '') then
- nomsu:append(suffix)
+ local indented = self:tree_to_nomsu(t, pop_comments, space)
+ if t.type == "Action" and not (tree.type == "Block" or tree.type == "FileChunks") then
+ indented:prepend("(..)\n ", pop_comments(t.source.start))
end
- return nomsu
- end
- local recurse
- recurse = function(t)
- return self:tree_to_nomsu(t, comments)
+ return indented
end
local _exp_0 = tree.type
if "FileChunks" == _exp_0 then
@@ -952,7 +1017,7 @@ do
if chunk.type == "Block" then
for line_no, line in ipairs(chunk) do
nomsu:append(pop_comments(line.source.start, '\n'))
- local line_nomsu = recurse(line)
+ local line_nomsu = self:tree_to_nomsu(line, pop_comments)
nomsu:append(line_nomsu)
if line_no < #chunk then
nomsu:append(line_nomsu:is_multiline() and "\n\n" or "\n")
@@ -979,43 +1044,25 @@ do
end
nomsu:append(bit)
next_space = ' '
+ elseif bit.type == "Block" then
+ nomsu:append(recurse(bit, #tostring(nomsu):match('[^\n]*$')))
+ pos = bit.source.stop
+ next_space = inline and " " or "\n.."
else
- local inline
- if bit.type == "Block" and #bit > 1 then
- inline = nil
- else
- local _inline = self:tree_to_inline_nomsu(bit)
- inline = (nomsu:trailing_line_len() + #tostring(_inline) < MAX_LINE) and _inline or nil
- end
- if bit.type == "Block" then
- nomsu:append(inline or recurse(bit))
- elseif bit.type == "Action" then
- nomsu:append(next_space)
- if inline then
- nomsu:append("(", inline, ")")
- else
- nomsu:append(NomsuCode(bit.source, "(..)\n ", pop_comments(bit.source.start), recurse(bit)))
- end
- else
- nomsu:append(next_space, (inline or recurse(bit)))
+ nomsu:append(next_space)
+ local bit_nomsu = recurse(bit, #tostring(nomsu):match('[^\n]*$'))
+ if bit.type == "Action" and not bit_nomsu:is_multiline() then
+ bit_nomsu:parenthesize()
end
+ nomsu:append(bit_nomsu)
pos = bit.source.stop
- next_space = inline and " " or "\n.."
+ next_space = bit_nomsu:is_multiline() and "\n.." or " "
end
end
nomsu:append(pop_comments(tree.source.stop, '\n'))
return nomsu
elseif "EscapedNomsu" == _exp_0 then
- local inline_nomsu = self:tree_to_inline_nomsu(tree)
- if not (#tostring(inline_nomsu) > MAX_LINE) then
- return inline_nomsu
- end
- 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, "\\", recurse(tree[1]))
- else
- return NomsuCode(tree.source, "\\(..)\n ", pop_comments(tree.source.start), recurse(tree[1]))
- end
+ return NomsuCode(tree.source, "\\", recurse(tree[1], 1))
elseif "Block" == _exp_0 then
local nomsu = NomsuCode(tree.source, pop_comments(tree.source.start))
for i, line in ipairs(tree) do
@@ -1029,13 +1076,8 @@ do
nomsu:append(pop_comments(tree.source.stop, '\n'))
return NomsuCode(tree.source, ":\n ", nomsu)
elseif "Text" == _exp_0 then
- 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)
+ local add_text
+ add_text = function(nomsu, tree)
for i, bit in ipairs(tree) do
if type(bit) == 'string' then
bit = Parser.escape(bit)
@@ -1043,156 +1085,97 @@ do
for j, line in ipairs(bit_lines) do
if j > 1 then
nomsu:append("\n")
+ elseif #line > 10 and nomsu:trailing_line_len() > MAX_LINE then
+ nomsu:append("\\\n..")
end
- 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
+ while #line > 0 do
+ local space = MAX_LINE - nomsu:trailing_line_len()
+ local split = find(line, " ", space, true)
+ if not split or split > space + 10 then
+ split = space + 10
+ end
+ if #line - split < 10 then
+ split = #line
+ end
+ local bite
+ bite, line = sub(line, 1, split), sub(line, split + 1, -1)
+ nomsu:append(bite)
+ if #line > 0 then
+ nomsu:append("\\\n..")
end
- else
- nomsu:append(line)
end
end
elseif bit.type == "Text" then
- nomsu:append(make_text(bit))
+ add_text(nomsu, bit)
else
- local interp_nomsu = self:tree_to_inline_nomsu(bit)
- if nomsu:trailing_line_len() + #tostring(interp_nomsu) <= MAX_LINE then
+ nomsu:append("\\")
+ local interp_nomsu = recurse(bit, #tostring(nomsu):match('[^\n]*$'))
+ if not (interp_nomsu:is_multiline()) then
if bit.type == "Var" then
if type(tree[i + 1]) == 'string' and not match(tree[i + 1], "^[ \n\t,.:;#(){}[%]]") then
interp_nomsu:parenthesize()
end
- elseif bit.type == "List" or bit.type == "Dict" then
- nomsu:append("\\", interp_nomsu)
- else
- 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..")
+ elseif bit.type ~= "List" and bit.type ~= "Dict" then
+ interp_nomsu:parenthesize()
end
end
+ nomsu:append(interp_nomsu)
+ if interp_nomsu:is_multiline() and i < #tree then
+ nomsu:append("\n..")
+ end
end
end
- return nomsu
end
- return NomsuCode(tree.source, '".."\n ', make_text(tree))
+ local nomsu = NomsuCode(tree.source)
+ add_text(nomsu, tree)
+ return NomsuCode(tree.source, '".."\n ', nomsu)
elseif "List" == _exp_0 then
- 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 inline = self:tree_to_inline_nomsu(item)
- local item_nomsu = self:tree_to_inline_nomsu(item)
- if item.type == "Block" then
- item_nomsu:parenthesize()
+ assert(item.type ~= "Block", "Didn't expect to find a Block inside a list")
+ if nomsu:trailing_line_len() == 0 then
+ nomsu:append(pop_comments(item.source.start))
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)
- elseif #tostring(item_nomsu) <= MAX_LINE then
- if nomsu:trailing_line_len() > 0 then
- nomsu:append("\n", pop_comments(item_nomsu.source.start))
- end
- nomsu:append(item_nomsu)
- else
- item_nomsu = recurse(item)
- if item.type == "Action" then
- nomsu:append("(..)\n ", pop_comments(item_nomsu.source.start), item_nomsu)
- else
- nomsu:append(item_nomsu)
- end
- if i < #tree then
- nomsu:append("\n")
- end
+ local inline_nomsu = self:tree_to_inline_nomsu(item)
+ local item_nomsu = #tostring(inline_nomsu) <= MAX_LINE and inline_nomsu or recurse(item, #tostring(nomsu):match('[^\n]*$'))
+ nomsu:append(item_nomsu)
+ if i < #tree then
+ nomsu:append((item_nomsu:is_multiline() or nomsu:trailing_line_len() + #tostring(item_nomsu) >= MAX_LINE) and '\n' or ', ')
end
end
nomsu:append(pop_comments(tree.source.stop, '\n'))
return NomsuCode(tree.source, "[..]\n ", nomsu)
elseif "Dict" == _exp_0 then
- 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()
+ assert(item.type == "DictEntry", "Only expected to find DictEntry items in a Dict")
+ if nomsu:trailing_line_len() == 0 then
+ nomsu:append(pop_comments(item.source.start))
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)
- elseif #tostring(item_nomsu) <= MAX_LINE then
- if nomsu:trailing_line_len() > 0 then
- nomsu:append("\n", pop_comments(item_nomsu.source.start))
- end
- nomsu:append(item_nomsu)
- else
- item_nomsu = recurse(item)
- if item.type == "Action" then
- nomsu:append("(..)\n ", pop_comments(item_nomsu.source.start), item_nomsu)
- else
- nomsu:append(item_nomsu)
- end
- if i < #tree then
- nomsu:append("\n")
- end
+ local inline_nomsu = self:tree_to_inline_nomsu(item)
+ local item_nomsu = #tostring(inline_nomsu) <= MAX_LINE and inline_nomsu or recurse(item, #tostring(nomsu):match('[^\n]*$'))
+ nomsu:append(item_nomsu)
+ if i < #tree then
+ nomsu:append((item_nomsu:is_multiline() or nomsu:trailing_line_len() + #tostring(item_nomsu) >= MAX_LINE) and '\n' or ', ')
end
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
+ local nomsu
if key.type == "Text" and #key == 1 and Parser.is_identifier(key[1]) then
- key_nomsu = NomsuCode(key.source, key[1])
+ nomsu = NomsuCode(key.source, key[1])
else
- key_nomsu = self:tree_to_inline_nomsu(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 = 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)
+ nomsu:parenthesize()
end
+ nomsu:append(": ", recurse(value, #tostring(nomsu)))
+ return nomsu
elseif "IndexChain" == _exp_0 or "Number" == _exp_0 or "Var" == _exp_0 then
return self:tree_to_inline_nomsu(tree)
else