aboutsummaryrefslogtreecommitdiff
path: root/nomsu_compiler.moon
diff options
context:
space:
mode:
authorBruce Hill <bitbucket@bruce-hill.com>2018-07-19 20:41:31 -0700
committerBruce Hill <bitbucket@bruce-hill.com>2018-07-19 20:42:09 -0700
commit47db74229deaf281ad02c8305c4e4d4c8dbd3d7d (patch)
treefac39ef65240c3de58b68a4f59bb93f2d4e622c6 /nomsu_compiler.moon
parent0eff1c77f250e6839086f41af0c79bb3e2e8ea39 (diff)
Fixed some bugs in trailing_line_len() and refactored tree_to_nomsu into
separate inline/not-inline functions.
Diffstat (limited to 'nomsu_compiler.moon')
-rw-r--r--nomsu_compiler.moon473
1 files changed, 242 insertions, 231 deletions
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}")