From bff93d386c1d54504f0b8c930f246966d307a9e5 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Tue, 24 Apr 2018 20:16:46 -0700 Subject: [PATCH] Refactor to improve indentation and move as_nomsu() into tree methods. --- core/control_flow.nom | 71 ++++++------ lua_obj.moon | 121 ++++++++------------- nomsu.moon | 248 ++---------------------------------------- nomsu.peg | 2 +- nomsu_tree.moon | 212 +++++++++++++++++++++++++++++++++++- 5 files changed, 302 insertions(+), 352 deletions(-) diff --git a/core/control_flow.nom b/core/control_flow.nom index 0f081fc..35e5fb5 100644 --- a/core/control_flow.nom +++ b/core/control_flow.nom @@ -15,16 +15,16 @@ immediately: compile [if %condition %if_body] to: Lua ".." if \(%condition as lua expr) then - \(%if_body as lua statements) + \(%if_body as lua statements) end parse [unless %condition %unless_body] as: if (not %condition) %unless_body compile [if %condition %if_body else %else_body, unless %condition %else_body else %if_body] to: Lua ".." if \(%condition as lua expr) then - \(%if_body as lua statements) + \(%if_body as lua statements) else - \(%else_body as lua statements) + \(%else_body as lua statements) end # Conditional expression (ternary operator) @@ -94,16 +94,17 @@ immediately: if %body has subtree % where: (%.type = "Action") and ((%'s stub) is "do next repeat") ..: - to %lua write "\n::continue_repeat::;" + to %lua write "\n ::continue_repeat::;" to %lua write "\nend --while-loop" if %body has subtree % where: (%.type = "Action") and ((%'s stub) is "stop repeating") ..: - %lua <- ".." - do -- scope of "stop repeating" label - \%lua - ::stop_repeat::; - end -- end of "stop repeating" label scope + %lua <- + Lua ".." + do -- scope of "stop repeating" label + \%lua + ::stop_repeat::; + end -- end of "stop repeating" label scope return %lua parse [repeat %body] as: repeat while (yes) %body parse [repeat until %condition %body] as: repeat while (not %condition) %body @@ -117,7 +118,7 @@ immediately: \(%body as lua statements) if %body has subtree % where (%.type = "Action") and ((%'s stub) is "do next repeat") - ..: to %lua write "\n::continue_repeat::;" + ..: to %lua write "\n ::continue_repeat::;" to %lua write "\nend --numeric for-loop" if %body has subtree % where: (%.type = "Action") and ((%'s stub) is "stop repeating") @@ -125,8 +126,8 @@ immediately: %lua <-: Lua ".." do -- scope of "stop repeating" label - \%lua - ::stop_repeat::; + \%lua + ::stop_repeat::; end -- end of "stop repeating" label scope return %lua @@ -153,7 +154,7 @@ immediately: (%.type = "Action") and ((%'s stub) is "do next %") and %.value.3.value is %var.value - ..: to %lua write "\n::continue_\(%var as lua identifier)::;" + ..: to %lua write "\n ::continue_\(%var as lua identifier)::;" to %lua write "\nend --numeric for-loop" if %body has subtree % where: @@ -161,11 +162,12 @@ immediately: ((%'s stub) is "stop %") and: %.value.2.value is %var.value ..: - to %lua write ".." - do -- scope for stopping for-loop - \%lua - ::stop_\(%var as lua identifier)::; - end -- end of scope for stopping for-loop + %lua <- + Lua ".." + do -- scope for stopping for-loop + \%lua + ::stop_\(%var as lua identifier)::; + end -- end of scope for stopping for-loop return %lua @@ -190,7 +192,7 @@ immediately: (%.type = "Action") and ((%'s stub) is "do next %") and %.value.3.value is %var.value - ..: to %lua write (Lua "\n::continue_\(%var as lua identifier)::;") + ..: to %lua write (Lua "\n ::continue_\(%var as lua identifier)::;") to %lua write "\nend --foreach-loop" if %body has subtree % where: (%.type = "Action") and @@ -221,13 +223,13 @@ immediately: (%.type = "Action") and ((%'s stub) is "do next %") and %.value.3.value is %key.value - ..: to %lua write (Lua "\n::continue_\(%key as lua identifier)::;") + ..: to %lua write (Lua "\n ::continue_\(%key as lua identifier)::;") if %body has subtree % where: (%.type = "Action") and ((%'s stub) is "do next %") and %.value.3.value is %value.value - ..: to %lua write (Lua "\n::continue_\(%value as lua identifier)::;") + ..: to %lua write (Lua "\n ::continue_\(%value as lua identifier)::;") to %lua write "\nend --foreach-loop" %stop_labels <- (Lua "") @@ -247,7 +249,8 @@ immediately: %lua <- Lua ".." do -- scope for stopping for % = % loop - \%lua\%stop_labels + \%lua + \%stop_labels end return %lua @@ -277,10 +280,8 @@ immediately: if: (%condition.type is "Word") and (%condition.value is "else") assume (not %is_first) or barf "'else' clause cannot be first in 'when % = ?' block" - to %code write ".." - - else - \(%action as lua statements) + to %code write "\nelse\n " + to %code write: %action as lua statements %seen_else <- (yes) ..else: assume (not %seen_else) or barf "'else' clause needs to be last in 'when' block" @@ -289,7 +290,7 @@ immediately: for %i=%condition in %fallthroughs: if (%i > 1): to %code write " or " to %code write %condition - to %code write " then\n" + to %code write " then\n " to %code write (%action as lua statements) %fallthroughs <- [] @@ -297,7 +298,7 @@ immediately: assume (%fallthroughs = []) or barf "Unfinished fallthrough conditions in 'when' block" assume ((length of %code) > 0) or barf "Empty body for 'when' block" - to %code write "\nend" + to %code write "\nend --when" return %code # Switch statement @@ -322,10 +323,8 @@ immediately: if: (%condition.type is "Word") and (%condition.value is "else") assume (not %is_first) or barf "'else' clause cannot be first in 'when % = ?' block" - to %code write ".." - - else - \(%action as lua statements) + to %code write "\nelse\n " + to %code write: %action as lua statements ..else: assume (not %seen_else) or barf "'else' clause needs to be last in 'when % = ?' block" to %code write "\("if" if %is_first else "\nelseif") " @@ -337,7 +336,7 @@ immediately: to %code write "branch_value == \%" ..else: to %code write "utils.equivalent(branch_value, \%)" - to %code write "then\n" + to %code write "then\n " to %code write (%action as lua statements) %fallthroughs <- [] @@ -390,8 +389,8 @@ immediately: compile [do %action] to: Lua ".." do - \(%action as lua statements) - end + \(%action as lua statements) + end --do compile [do %action then always %final_action] to: Lua ".." @@ -409,5 +408,5 @@ immediately: if not fell_through then return ret1; end - end + end --do-then-always diff --git a/lua_obj.moon b/lua_obj.moon index a7c7ff6..2afe13d 100644 --- a/lua_obj.moon +++ b/lua_obj.moon @@ -62,6 +62,7 @@ Source = immutable {"filename","start","stop"}, { class Code new: (@source, ...)=> + @indents = {} @bits = {...} if type(@source) == 'string' filename,start,stop = @source\match("^(.-)%[(%d+):(%d+)%]$") @@ -72,31 +73,19 @@ class Code else @source = Source(@source, 1, #self+1) assert(@source == nil or Source\is_instance(@source)) - for b in *@bits - assert(not Source\is_instance(b)) - - clone: => - cls = @__class - copy = cls(@source, unpack(@bits)) - copy.is_value = @is_value - for k,v in pairs @free_vars - copy.free_vars[k] = v - return copy - - __tostring: => - buff = {} + indent = 0 for i,b in ipairs @bits - buff[#buff+1] = tostring(b) - ret = concat(buff, "") - return ret - - __len: => - len = 0 - for b in *@bits - len += #b - return len - + assert(not Source\is_instance(b)) + if type(b) == 'string' + if spaces = b\match("\n([ ]*)[^\n]*$") + indent = #spaces + elseif indent != 0 + @indents[i] = indent + @current_indent = indent + @__str = nil + sub: (start,stop)=> + -- TODO: implement this better str = tostring(self)\sub(start,stop) cls = @__class return cls(@source\sub(start,stop), str) @@ -105,15 +94,31 @@ class Code n = select("#",...) bits = @bits for i=1,n - bits[#bits+1] = select(i, ...) + b = select(i, ...) + bits[#bits+1] = b + if type(b) == 'string' + if spaces = b\match("\n([ ]*)[^\n]*$") + @current_indent = #spaces + elseif @current_indent != 0 + @indents[#bits] = @current_indent + @__str = nil prepend: (...)=> n = select("#",...) - bits = @bits + bits, indents = @bits, @indents for i=#bits+n,n+1,-1 bits[i] = bits[i-n] for i=1,n bits[i] = select(i, ...) + @current_indent = 0 + for i,b in ipairs(bits) + if type(b) == 'string' + if spaces = b\match("\n([ ]*)[^\n]*$") + @current_indent = #spaces + elseif @current_indent != 0 + indents[i] = @current_indent + else indents[i] = nil + @__str = nil class Lua extends Code new: (...)=> @@ -181,56 +186,23 @@ class Lua extends Code if bit.__class == Lua gather_from bit gather_from self - @remove_free_vars to_declare if #to_declare > 0 + @remove_free_vars unpack(to_declare) @prepend "local #{concat to_declare, ", "};\n" - stringify: => - if @__str == nil - buff = {} - for i,b in ipairs @bits - if type(b) != 'string' - b = b\stringify! - buff[#buff+1] = b - @__str = concat(buff, "") - return @__str __tostring: => if @__str == nil - buff = {} + buff, indents = {}, @indents for i,b in ipairs @bits - buff[#buff+1] = tostring(b) + b = tostring(b) + if indents[i] + b = b\gsub("\n", "\n"..((" ")\rep(indents[i]))) + buff[#buff+1] = b @__str = concat(buff, "") return @__str __len: => - len = 0 - for b in *@bits - len += #b - return len - - append: (...)=> - n = select("#",...) - bits = @bits - for i=1,n - bit = select(i, ...) - bits[#bits+1] = bit - if type(bit) != 'string' and not bit.is_value and #@bits > 0 - bits[#bits+1] = "\n" - @__str = nil - - prepend: (...)=> - n = select("#",...) - bits = @bits - insert_index = 1 - -- TODO: optimize? - for i=1,n - bit = select(i, ...) - insert bits, insert_index, bit - insert_index += 1 - if type(bit) != 'string' and not bit.is_value and insert_index < #@bits + 1 - insert bits, insert_index, "\n" - insert_index += 1 - @__str = nil + #tostring(self) make_offset_table: => -- Return a mapping from output (lua) character number to input (nomsu) character number @@ -260,16 +232,17 @@ class Lua extends Code class Nomsu extends Code __tostring: => - buff = {} - for i,b in ipairs @bits - buff[#buff+1] = tostring(b) - ret = concat(buff, "") - return ret + if @__str == nil + buff, indents = {}, @indents + for i,b in ipairs @bits + b = tostring(b) + if indents[i] + b = b\gsub("\n", "\n"..((" ")\rep(indents[i]))) + buff[#buff+1] = b + @__str = concat(buff, "") + return @__str __len: => - len = 0 - for b in *@bits - len += #b - return len + #tostring(self) return {:Code, :Nomsu, :Lua, :Source} diff --git a/nomsu.moon b/nomsu.moon index dd5b07d..60854b2 100755 --- a/nomsu.moon +++ b/nomsu.moon @@ -365,7 +365,7 @@ class NomsuCompiler run_lua: (lua)=> assert(type(lua) != 'string', "Attempt to run lua string instead of Lua (object)") - lua_string = lua\stringify! + lua_string = tostring(lua) --metadata = lua\make_offset_table! --LUA_METADATA[metadata.lua_filename] = metadata if rawget(FILE_CACHE, lua.source.filename) == nil @@ -390,238 +390,8 @@ class NomsuCompiler lua = Lua(tree.source, "return ",@tree_to_lua(tree),";") return @run_lua(lua) - tree_to_nomsu: (tree, indentation="", max_line=80, expr_type=nil)=> - -- Convert a tree into nomsu code that satisfies the max line requirement or nil - -- if that's not possible - -- expr_type is either: - -- nil for code that goes at the top level and can contain anything - -- "noeol" for code that can contain anything except an end-of-line component - -- like a colon (i.e. it already occurs after a colon on the same line) - -- "inline" for code that cannot contain indented code or an end-of-line component - -- e.g. code that is meant to go inside parentheses - assert tree, "No tree provided to tree_to_nomsu." - assert Types.is_node(tree), "Invalid tree: #{repr(tree)}" - join_lines = (lines)-> - for line in *lines - if #indentation + #line > max_line - return nil - return concat(lines, "\n"..indentation) - - is_operator = (tok)-> tok and tok.type == "Word" and NOMSU_DEFS.operator\match(tok.value) - - local inline_expression, noeol_expression, expression - inline_expression = (tok)-> - switch tok.type - when "Block" - if #tok.value > 1 then return nil - nomsu = inline_expression tok.value - return nomsu and "(: #{nomsu})" - when "Action" - buff = "" - for i,bit in ipairs tok.value - if bit.type == "Word" - if i == 1 or (is_operator(bit) and is_operator(tok.value[i-1])) - buff ..= bit.value - else buff ..= " "..bit.value - else - nomsu = inline_expression bit - return nil unless nomsu - unless i == 1 or bit.type == "Block" - buff ..= " " - buff ..= if bit.type == "Action" - "("..nomsu..")" - else nomsu - return buff - when "IndexChain" - bits = {} - for bit in *tok.value - nomsu = inline_expression bit - return nil unless nomsu - insert bits, nomsu - return concat(bits, ".") - when "List" - bits = {} - for bit in *tok.value - nomsu = inline_expression bit - return nil unless nomsu - insert bits, nomsu - return "["..concat(bits, ", ").."]" - when "Dict" - bits = {} - for bit in *tok.value - key_nomsu = if bit.key.type == "Word" - bit.key.value - else inline_expression bit.key - return nil unless key_nomsu - if bit.key.type == "Action" - key_nomsu = "("..key_nomsu..")" - value_nomsu = inline_expression bit.value - return nil unless value_nomsu - insert bits, key_nomsu.."="..value_nomsu - return "{"..concat(bits, ", ").."}" - when "Text" - buff = '"' - for bit in *tok.value - if type(bit) == 'string' - -- Force indented text - return nil if bit\find("\n") - buff ..= bit\gsub("\\","\\\\")\gsub("\n","\\n") - else - nomsu = inline_expression(bit) - return nil unless nomsu - buff ..= if bit.type == "Var" or bit.type == "List" or bit.type == "Dict" - "\\"..nomsu - else "\\("..nomsu..")" - if #buff > max_line then return nil - return buff..'"' - when "Nomsu" - nomsu = inline_expression(tok.value) - return nil if not nomsu - return "\\("..nomsu..")" - when "Number" then tostring(tok.value) - when "Var" then "%"..tok.value - else return nil - - noeol_expression = (tok)-> - nomsu = inline_expression(tok) - if nomsu and #nomsu < max_line - return nomsu - switch tok.type - when "Block" - buff = ":" - for line in *tok.value - nomsu = expression(line) - return nil unless nomsu - buff ..= "\n "..@indent(nomsu) - return buff - when "Action" - nomsu = expression(tok) - return nil unless nomsu - return "(..)\n "..@indent(nomsu) - when "IndexChain" - return nil - when "List" - buff = "[..]" - line = "\n " - for bit in *tok.value - nomsu = inline_expression bit - if line != "\n " and #line + #", " + #nomsu > max_line - buff ..= line - line = "\n " - sep = line == "\n " and "" or ", " - if nomsu - line ..= sep..nomsu - if #line >= max_line - buff ..= line - line = "\n " - else - line ..= sep..expression(bit) - buff ..= line - line = "\n " - if line ~= "\n " - buff ..= line - return buff - when "Dict" - buff = "{..}" - line = "\n " - for bit in *tok.value - key_nomsu = inline_expression bit.key - return nil unless key_nomsu - if bit.key.type == "Action" - key_nomsu = "("..key_nomsu..")" - value_nomsu = inline_expression bit.value - if value_nomsu and #key_nomsu + #value_nomsu < max_line - line ..= key_nomsu.."="..value_nomsu.."," - if #line >= max_line - buff ..= line - line = "\n " - else - line ..= key_nomsu.."="..expression(bit.value) - buff ..= line - line = "\n " - if line ~= "\n " - buff ..= line - return buff - when "Text" - buff = '".."\n ' - for bit in *tok.value - if type(bit) == 'string' - buff ..= bit\gsub("\\","\\\\")\gsub("\n","\n ") - else - nomsu = inline_expression(bit) - return nil unless nomsu - buff ..= if bit.type == "Var" or bit.type == "List" or bit.type == "Dict" - "\\"..nomsu - else "\\("..nomsu..")" - return buff - when "Nomsu" - nomsu = expression(tok.value) - return nil if not nomsu - return "\\(..)\n "..@indent(nomsu) - when "Comment" - if tok.value\find("\n") - return "#.."..tok.value\gsub("\n","\n ") - else - return "#"..tok.value - else return inline_expression(tok) - - expression = (tok)-> - nomsu = inline_expression(tok) - if nomsu and #nomsu < max_line - return nomsu - switch tok.type - when "Block" - if #tok.value == 1 - nomsu = if tok.value[1].type == "Action" - inline_expression(tok.value[1]) - else - noeol_expression(tok.value[1]) - if nomsu and #(nomsu\match("[^\n]*")) < max_line - return ": "..nomsu - return noeol_expression(tok) - when "Action" - -- The hard task - buff = "" - for i,bit in ipairs tok.value - if bit.type == "Word" - if i == 1 or (is_operator(bit) and is_operator(tok.value[i-1])) or buff\sub(-2,-1) == ".." - buff ..= bit.value - else - buff ..= " "..bit.value - else - nomsu = inline_expression(bit) - if nomsu and #nomsu < max_line - if bit.type == "Action" - nomsu = "("..nomsu..")" - else - nomsu = expression(bit) - return nil unless nomsu - if bit.type == "Action" - nomsu = "(..)\n "..@indent(nomsu) - if i < #tok.value - nomsu ..= "\n.." - unless i == 1 or bit.type == "Block" - buff ..= " " - buff ..= nomsu - return buff - when "File" - lines = {} - for line in *tree.value - nomsu = expression(line) - unless nomsu - error "Failed to produce output for:\n#{colored.yellow line.source\get_text!}", 0 - - insert lines, nomsu - return concat lines, "\n" - when "Comment" - if tok.value\find("\n") - return "#.."..tok.value\gsub("\n","\n ") - else - return "#"..tok.value - else return noeol_expression(tok) - - return expression(tree) - + tree_to_nomsu: (tree)=> + return tree\as_nomsu! value_to_nomsu: (value)=> switch type(value) @@ -739,7 +509,7 @@ class NomsuCompiler tree_with_replaced_vars: (tree, replacements)=> return @tree_map tree, (t)-> if t.type == "Var" - id = t\as_lua(self)\stringify! + id = tostring(t\as_lua(self)) if replacements[id] != nil return replacements[id] @@ -801,7 +571,7 @@ class NomsuCompiler lua\convert_to_statements! lua\declare_locals! nomsu\run_lua(lua) - return Lua(@source, "if IMMEDIATE then\n", lua, "\nend") + return Lua(@source, "if IMMEDIATE then\n ", lua, "\nend") add_lua_bits = (lua, code)-> if code.type != "Text" @@ -845,7 +615,7 @@ class NomsuCompiler @define_compile_action "lua> %code", get_line_no!, (_code)=> if _code.type != "Text" return Lua.Value @source, "nomsu:run_lua(Lua(",repr(_code.source), - ", ",repr(nomsu\tree_to_lua(_code)\stringify!),"))" + ", ",repr(tostring(nomsu\tree_to_lua(_code))),"))" lua = Lua(_code.source) for bit in *_code.value @@ -862,7 +632,7 @@ class NomsuCompiler @define_compile_action "=lua %code", get_line_no!, (_code)=> if _code.type != "Text" return Lua.Value @source, "nomsu:run_lua(Lua(",repr(_code.source), - ", ",repr(nomsu\tree_to_lua(_code)\stringify!),"))" + ", ",repr(tostring(nomsu\tree_to_lua(_code))),"))" lua = Lua.Value(@source) for bit in *_code.value @@ -954,10 +724,10 @@ if arg and debug_getinfo(2).func != require if args.flags["-p"] nomsu.environment.print = -> compile_fn = (code)-> - io.output!\write("local IMMEDIATE = true;\n"..(code\stringify!)) + io.output!\write("local IMMEDIATE = true;\n"..tostring(code)) elseif args.output compile_fn = (code)-> - io.open(args.output, 'w')\write("local IMMEDIATE = true;\n"..(code\stringify!)) + io.open(args.output, 'w')\write("local IMMEDIATE = true;\n"..tostring(code)) if args.input\match(".*%.lua") dofile(args.input)(nomsu, {}) diff --git a/nomsu.peg b/nomsu.peg index bf2c639..e4ca686 100644 --- a/nomsu.peg +++ b/nomsu.peg @@ -5,7 +5,7 @@ file (File): (%nl ignored_line)* (!. / (("" -> "Parse error") => error)?) |} -> Tuple -shebang: "#!" [^%nl]* %nl +shebang: "#!" [^%nl]* (!. / %nl) statement: action / expression diff --git a/nomsu_tree.moon b/nomsu_tree.moon index 421e02a..fcef992 100644 --- a/nomsu_tree.moon +++ b/nomsu_tree.moon @@ -2,6 +2,7 @@ -- as well as the logic for converting them to Lua code. utils = require 'utils' re = require 're' +lpeg = require 'lpeg' {:repr, :stringify, :min, :max, :equivalent, :set, :is_list, :sum} = utils immutable = require 'immutable' {:insert, :remove, :concat} = table @@ -42,17 +43,33 @@ Tree "File", line_lua = line\as_lua(nomsu) if not line_lua error("No lua produced by #{repr line}", 0) - if i < #@value + if i > 1 lua\append "\n" lua\convert_to_statements! lua\append line_lua lua\declare_locals! return lua + as_nomsu: (inline=false)=> + return nil if inline + nomsu = Nomsu(@source) + for i, line in ipairs @value + nomsu\append assert(line\as_nomsu!, "Could not convert line to nomsu: #{line}") + if i < #@value + nomsu\append "\n" + return nomsu + Tree "Nomsu", as_lua: (nomsu)=> Lua.Value(@source, "nomsu:parse(Nomsu(",repr(@value.source),", ",repr(tostring(@value.source\get_text!)),")).value[1]") + as_nomsu: (inline=false)=> + nomsu = @value\as_nomsu(true) + if nomsu == nil and not inline + nomsu = @value\as_nomsu! + return nomsu and Nomsu(@source, "\\:\n ", nomsu) + return nomsu and Nomsu(@source, "\\(", nomsu, ")") + Tree "Block", as_lua: (nomsu)=> if #@value == 1 @@ -60,12 +77,24 @@ Tree "Block", lua = Lua(@source) for i,line in ipairs @value line_lua = line\as_lua(nomsu) - if i < #@value + if i > 1 lua\append "\n" line_lua\convert_to_statements! lua\append line_lua return lua + as_nomsu: (inline=false)=> + if inline + if #@value == 1 + return @value[1]\as_nomsu(true) + else return nil + nomsu = Nomsu(@source) + for i, line in ipairs @value + nomsu\append assert(line\as_nomsu!, "Could not convert line to nomsu: #{line}") + if i < #@value + nomsu\append "\n" + return nomsu + math_expression = re.compile [[ "%" (" " [*/^+-] " %")+ ]] Tree "Action", as_lua: (nomsu)=> @@ -127,6 +156,51 @@ Tree "Action", [(t.type == "Word" and t.value or "%#{t.value}") for t in *@value] else [(t.type == "Word" and t.value or "%") for t in *@value] return concat(bits, " ") + + as_nomsu: (inline=false)=> + if inline + nomsu = Nomsu(@source) + for i,bit in ipairs @value + if bit.type == "Word" + if i > 1 + nomsu\append " " + nomsu\append bit.value + else + arg_nomsu = bit\as_nomsu(true) + return nil unless arg_nomsu + unless i == 1 + nomsu\append " " + if bit.type == "Action" + arg_nomsu\parenthesize! + nomsu\append arg_nomsu + return nomsu + else + inline_version = @as_nomsu(true) + if inline_version and #inline_version <= 80 + return inline_version + nomsu = Nomsu(@source) + spacer = nil + for i,bit in ipairs @value + if spacer + nomsu\append spacer + + if bit.type == "Word" + nomsu\append bit.value + spacer = " " + else + arg_nomsu = bit\as_nomsu(true) + if arg_nomsu and #arg_nomsu < 80 + if bit.type == "Action" + arg_nomsu\parenthesize! + spacer = " " + else + arg_nomsu = bit\as_nomsu! + return nil unless nomsu + if bit.type == "Action" + nomsu\append "\n ", nomsu + spacer = "\n.." + nomsu\append arg_nomsu + return nomsu Tree "Text", @@ -158,6 +232,42 @@ Tree "Text", lua\parenthesize! return lua + as_nomsu: (inline=false)=> + if inline + nomsu = Nomsu(@source, '"') + for bit in *@value + if type(bit) == 'string' + -- Force indented text + return nil if bit\find("\n") + -- TODO: unescape better + nomsu\append (bit\gsub("\\","\\\\")\gsub("\n","\\n")) + else + interp_nomsu = bit\as_nomsu(true) + if interp_nomsu + if bit.type != "Word" and bit.type != "List" and bit.type != "Dict" and bit.type != "Text" + interp_nomsu\parenthesize! + nomsu\append "\\", interp_nomsu + else return nil + nomsu\append '"' + if #nomsu > 80 then return nil + else + nomsu = Nomsu(@source, '".."\n ') + for i, bit in ipairs @value + if type(bit) == 'string' + nomsu\append (bit\gsub("\\","\\\\")\gsub("\n","\n ")) + else + if interp_nomsu + if bit.type != "Word" and bit.type != "List" and bit.type != "Dict" and bit.type != "Text" + interp_nomsu\parenthesize! + nomsu\append "\\", interp_nomsu + else + interp_nomsu = bit\as_nomsu! + return nil unless interp_nomsu + nomsu\append "\\\n ", interp_nomsu + if i < #@value + nomsu\append "\n.." + return nomsu + Tree "List", as_lua: (nomsu)=> lua = Lua.Value @source, "{" @@ -183,6 +293,38 @@ Tree "List", lua\append "}" return lua + as_nomsu: (inline=false)=> + if inline + nomsu = Nomsu(@source, "[") + for i, item in ipairs @value + item_nomsu = item\as_nomsu(true) + return nil unless item_nomsu + if i > 1 + nomsu\append ", " + nomsu\append item_nomsu + nomsu\append "]" + return nomsu + else + nomsu = Nomsu(@source, "[..]") + line = Nomsu(@source, "\n ") + for item in *@value + item_nomsu = item\as_nomsu(true) + if item_nomsu and #line + #", " + #item_nomsu <= 80 + if #line.bits > 1 + line\append ", " + line\append item_nomsu + else + unless item_nomsu + item_nomsu = item\as_nomsu! + return nil unless item_nomsu + if #line.bits > 1 + nomsu\append line + line = Nomsu(bit.source, "\n ") + line\append item_nomsu + if #line.bits > 1 + nomsu\append line + return nomsu + Tree "Dict", as_lua: (nomsu)=> lua = Lua.Value @source, "{" @@ -223,6 +365,46 @@ Tree "Dict", lua\append "}" return lua + as_nomsu: (inline=false)=> + if inline + nomsu = Nomsu(@source, "{") + for i, entry in ipairs @value + key_nomsu = entry.key\as_nomsu(true) + return nil unless key_nomsu + if entry.key.type == "Action" + key_nomsu\parenthesize! + value_nomsu = entry.value\as_nomsu(true) + return nil unless value_nomsu + if i > 1 + nomsu\append ", " + nomsu\append key_nomsu,":",value_nomsu + nomsu\append "}" + return nomsu + else + nomsu = Nomsu(@source, "{..}") + line = Nomsu(@source, "\n ") + for entry in *@value + key_nomsu = entry.key\as_nomsu(true) + return nil unless key_nomsu + if entry.key.type == "Action" + key_nomsu\parenthesize! + value_nomsu = entry.value\as_nomsu(true) + if value_nomsu and #line + #", " + #key_nomsu + #":" + #value_nomsu <= 80 + if #line.bits > 1 + line\append ", " + line\append key_nomsu,":",value_nomsu + else + unless value_nomsu + value_nomsu = entry.value\as_nomsu! + return nil unless value_nomsu + if #line.bits > 1 + nomsu\append line + line = Nomsu(bit.source, "\n ") + line\append key_nomsu,":",value_nomsu + if #line.bits > 1 + nomsu\append line + return nomsu + Tree "IndexChain", as_lua: (nomsu)=> lua = @value[1]\as_lua(nomsu) @@ -251,9 +433,22 @@ Tree "IndexChain", lua\append "[",key_lua,"]" return lua + as_nomsu: (inline=false)=> + nomsu = Nomsu(@source) + for i, bit in ipairs @value + if i > 1 + nomsu\append "." + bit_nomsu = bit\as_nomsu(true) + return nil unless bit_nomsu + nomsu\append bit_nomsu + return nomsu + Tree "Number", as_lua: (nomsu)=> Lua.Value(@source, tostring(@value)) + + as_nomsu: (inline=false)=> + return Nomsu(@source, tostring(@value)) Tree "Var", as_lua: (nomsu)=> @@ -261,12 +456,25 @@ Tree "Var", if verboten == "_" then "__" else ("_%x")\format(verboten\byte!)) Lua.Value(@source, lua_id) + as_nomsu: (inline=false)=> + return Nomsu(@source, "%", @value) + Tree "Word", as_lua: (nomsu)=> error("Attempt to convert Word to lua") + as_nomsu: (inline=false)=> + return Nomsu(@source, @value) + Tree "Comment", as_lua: (nomsu)=> Lua(@source, "--"..@value\gsub("\n","\n--").."\n") + as_nomsu: (inline=false)=> + return nil if inline + if @value\match("\n") + return Nomsu(@source, "#..", @value\gsub("\n", "\n ")) + else + return Nomsu(@source, "#", @value) + return Types