aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bitbucket@bruce-hill.com>2018-04-24 20:16:46 -0700
committerBruce Hill <bitbucket@bruce-hill.com>2018-04-24 20:17:08 -0700
commitbff93d386c1d54504f0b8c930f246966d307a9e5 (patch)
tree4e5a7cab137ab92c8790e8fc6878b55bf90dfdce
parent34a2f50ebc8b1d564b0061b5093b2736e365b29a (diff)
Refactor to improve indentation and move as_nomsu() into tree methods.
-rw-r--r--core/control_flow.nom71
-rw-r--r--lua_obj.moon121
-rwxr-xr-xnomsu.moon248
-rw-r--r--nomsu.peg2
-rw-r--r--nomsu_tree.moon212
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