aboutsummaryrefslogtreecommitdiff
path: root/nomsu_tree.moon
diff options
context:
space:
mode:
authorBruce Hill <bitbucket@bruce-hill.com>2018-05-16 18:12:56 -0700
committerBruce Hill <bitbucket@bruce-hill.com>2018-05-16 18:13:02 -0700
commit6f6c4377b236902566794c3d06820f3fdd7ec28c (patch)
treea3074d4d7c46585a9ece036455ff97b9ab12effc /nomsu_tree.moon
parentaf9dc0702568dc45b8809523dde760bb99aafbcb (diff)
Initial working version.
Diffstat (limited to 'nomsu_tree.moon')
-rw-r--r--nomsu_tree.moon253
1 files changed, 128 insertions, 125 deletions
diff --git a/nomsu_tree.moon b/nomsu_tree.moon
index ae345cc..11fed94 100644
--- a/nomsu_tree.moon
+++ b/nomsu_tree.moon
@@ -13,46 +13,57 @@ Types.is_node = (n)->
type(n) == 'userdata' and getmetatable(n) and Types[n.type] == getmetatable(n)
-- Helper method:
-Tree = (name, methods)->
+Tree = (name, kind, methods)->
+ assert((kind == 'single') or (kind == 'multi'))
+ is_multi = (kind == 'multi')
with methods
- .__tostring = => "#{@name}(#{repr(@value)}, #{repr @source})"
- .with_value = (value)=> getmetatable(self)(value, @source)
+ .with_value = (value)=> getmetatable(self)(value)
.type = name
.name = name
- .original_nomsu = =>
- leading_space = 0
- src_file = FILE_CACHE[@source.filename]
- while src_file\sub(@source.start-leading_space-1, @source.start-leading_space-1) == " "
- leading_space += 1
- if src_file\sub(@source.start-leading_space-1, @source.start-leading_space-1) != "\n"
- leading_space = 0
- ret = tostring(@source\get_text!)\gsub("\n"..((" ")\rep(leading_space)), "\n")
- return ret
- .map = (fn)=>
- if mapped = fn(self)
- return mapped
- if Tuple\is_instance(@value)
- return @with_value(Tuple(unpack([v.map and v\map(fn) or v for v in *@value])))
- return self
+ .is_multi = is_multi
+ if is_multi
+ .__tostring = => "#{@name}(#{table.concat [repr(v) for v in *@], ', '})"
+ .map = (fn)=>
+ if ret = fn(@)
+ return ret
+ new_vals = [v.map and v\map(fn) or v for v in *@]
+ ret = getmetatable(self)(unpack(new_vals))
+ return ret
+ else
+ .__tostring = => "#{@name}(#{repr(@value)})"
+ .map = (fn)=> fn(@) or @
- Types[name] = immutable {"value","source"}, methods
+ if is_multi
+ Types[name] = immutable nil, methods
+ else
+ Types[name] = immutable {"value"}, methods
-Tree "Nomsu",
+Tree "EscapedNomsu", 'single',
as_lua: (nomsu)=>
- Lua.Value(@source, "nomsu:parse(Nomsu(",repr(@value.source),", ",repr(tostring(@value\as_nomsu(true))),"))")
+ make_tree = (t)->
+ if type(t) != 'userdata'
+ return repr(t)
+ if t.is_multi
+ bits = [make_tree(bit) for bit in *t]
+ return t.type.."("..table.concat(bits, ", ")..")"
+ else
+ return t.type.."("..make_tree(t.value)..")"
+ Lua.Value nil, make_tree(@value)
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, ")")
+ return nomsu and Nomsu nil, "\\:\n ", nomsu
+ return nomsu and Nomsu nil, "\\(", nomsu, ")"
+
+ map: (fn)=> fn(@) or @\map(fn)
-Tree "Block",
+Tree "Block", 'multi',
as_lua: (nomsu)=>
- lua = Lua(@source)
- for i,line in ipairs @value
+ lua = Lua!
+ for i,line in ipairs @
line_lua = line\as_lua(nomsu)
if i > 1
lua\append "\n"
@@ -61,31 +72,31 @@ Tree "Block",
as_nomsu: (inline=false)=>
if inline
- nomsu = Nomsu(@source)
- for i,line in ipairs @value
+ nomsu = Nomsu!
+ for i,line in ipairs @
if i > 1
nomsu\append "; "
line_nomsu = line\as_nomsu(true)
return nil unless line_nomsu
nomsu\append line_nomsu
return nomsu
- nomsu = Nomsu(@source)
- for i, line in ipairs @value
+ nomsu = Nomsu!
+ for i, line in ipairs @
line = assert(line\as_nomsu(nil, true), "Could not convert line to nomsu")
nomsu\append line
- if i < #@value
+ if i < #@
nomsu\append "\n"
if tostring(line)\match("\n")
nomsu\append "\n"
return nomsu
math_expression = re.compile [[ ([+-] " ")* "%" (" " [*/^+-] (" " [+-])* " %")+ !. ]]
-Tree "Action",
+Tree "Action", 'multi',
as_lua: (nomsu)=>
stub = @get_stub!
compile_action = nomsu.environment.COMPILE_ACTIONS[stub]
if compile_action
- args = [arg for arg in *@value when arg.type != "Word"]
+ args = [arg for arg in *@ when arg.type != "Word"]
-- Force all compile-time actions to take a tree location
args = [args[p-1] for p in *nomsu.environment.ARG_ORDERS[compile_action][stub]]
-- Force Lua to avoid tail call optimization for debugging purposes
@@ -93,33 +104,31 @@ Tree "Action",
if not ret then error("Failed to produce any Lua")
return ret
action = rawget(nomsu.environment.ACTIONS, stub)
- lua = Lua.Value(@source)
+ lua = Lua.Value!
if not action and math_expression\match(stub)
-- This is a bit of a hack, but this code handles arbitrarily complex
-- math expressions like 2*x + 3^2 without having to define a single
-- action for every possibility.
- for i,tok in ipairs @value
+ for i,tok in ipairs @
if tok.type == "Word"
lua\append tok.value
else
tok_lua = tok\as_lua(nomsu)
unless tok_lua.is_value
- src = tok.source\get_text!
- error("non-expression value inside math expression: #{colored.yellow src}")
+ error("non-expression value inside math expression: #{colored.yellow repr(tok)}")
if tok.type == "Action"
tok_lua\parenthesize!
lua\append tok_lua
- if i < #@value
+ if i < #@
lua\append " "
return lua
args = {}
- for i, tok in ipairs @value
+ for i, tok in ipairs @
if tok.type == "Word" then continue
arg_lua = tok\as_lua(nomsu)
unless arg_lua.is_value
- line, src = tok.source\get_line!, tok.source\get_text!
- error "#{line}: Cannot use:\n#{colored.yellow src}\nas an argument to #{stub}, since it's not an expression, it produces: #{repr arg_lua}", 0
+ error "Cannot use:\n#{colored.yellow repr(tok)}\nas an argument to #{stub}, since it's not an expression, it produces: #{repr arg_lua}", 0
insert args, arg_lua
if action
@@ -136,14 +145,14 @@ Tree "Action",
get_stub: (include_names=false)=>
bits = if include_names
- [(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]
+ [(t.type == "Word" and t.value or "%#{t.value}") for t in *@]
+ else [(t.type == "Word" and t.value or "%") for t in *@]
return concat(bits, " ")
as_nomsu: (inline=false, can_use_colon=false)=>
if inline
- nomsu = Nomsu(@source)
- for i,bit in ipairs @value
+ nomsu = Nomsu!
+ for i,bit in ipairs @
if bit.type == "Word"
if i > 1
nomsu\append " "
@@ -158,11 +167,11 @@ Tree "Action",
nomsu\append arg_nomsu
return nomsu
else
- nomsu = Nomsu(@source)
+ nomsu = Nomsu!
next_space = ""
-- TODO: track line length as we go and use 80-that instead of 80 for wrapping
last_colon = nil
- for i,bit in ipairs @value
+ for i,bit in ipairs @
if bit.type == "Word"
nomsu\append next_space, bit.value
next_space = " "
@@ -189,9 +198,9 @@ Tree "Action",
-- These types carry their own indentation
if bit.type != "List" and bit.type != "Dict" and bit.type != "Text"
if i == 1
- arg_nomsu = Nomsu(bit.source, "(..)\n ", arg_nomsu)
+ arg_nomsu = Nomsu(nil, "(..)\n ", arg_nomsu)
else
- arg_nomsu = Nomsu(bit.source, "\n ", arg_nomsu)
+ arg_nomsu = Nomsu(nil, "\n ", arg_nomsu)
if last_colon == i-1 and (bit.type == "Action" or bit.type == "Block")
next_space = ""
@@ -202,11 +211,11 @@ Tree "Action",
next_space = "\n.."
return nomsu
-Tree "Text",
+Tree "Text", 'multi',
as_lua: (nomsu)=>
- lua = Lua.Value(@source)
+ lua = Lua.Value!
string_buffer = ""
- for bit in *@value
+ for bit in *@
if type(bit) == "string"
string_buffer ..= bit
continue
@@ -216,11 +225,10 @@ Tree "Text",
string_buffer = ""
bit_lua = bit\as_lua(nomsu)
unless bit_lua.is_value
- line, src = bit.source\get_line!, bit.source\get_text!
- error "#{line}: Cannot use #{colored.yellow bit} as a string interpolation value, since it's not an expression.", 0
+ error "Cannot use #{colored.yellow repr(bit)} as a string interpolation value, since it's not an expression.", 0
if #lua.bits > 0 then lua\append ".."
if bit.type != "Text"
- bit_lua = Lua.Value(bit.source, "stringify(",bit_lua,")")
+ bit_lua = Lua.Value(nil, "stringify(",bit_lua,")")
lua\append bit_lua
if string_buffer ~= "" or #lua.bits == 0
@@ -233,8 +241,8 @@ Tree "Text",
as_nomsu: (inline=false)=>
if inline
- nomsu = Nomsu(@source, '"')
- for bit in *@value
+ nomsu = Nomsu(nil, '"')
+ for bit in *@
if type(bit) == 'string'
-- TODO: unescape better?
nomsu\append (bit\gsub("\\","\\\\")\gsub("\n","\\n"))
@@ -251,8 +259,8 @@ Tree "Text",
inline_version = @as_nomsu(true)
if inline_version and #inline_version <= MAX_LINE
return inline_version
- nomsu = Nomsu(@source, '".."\n ')
- for i, bit in ipairs @value
+ nomsu = Nomsu(nil, '".."\n ')
+ for i, bit in ipairs @
if type(bit) == 'string'
nomsu\append (bit\gsub("\\","\\\\")\gsub("\n","\n "))
else
@@ -265,19 +273,18 @@ Tree "Text",
interp_nomsu = bit\as_nomsu!
return nil unless interp_nomsu
nomsu\append "\\\n ", interp_nomsu
- if i < #@value
+ if i < #@
nomsu\append "\n .."
return nomsu
-Tree "List",
+Tree "List", 'multi',
as_lua: (nomsu)=>
- lua = Lua.Value @source, "{"
+ lua = Lua.Value nil, "{"
line_length = 0
- for i, item in ipairs @value
+ for i, item in ipairs @
item_lua = item\as_lua(nomsu)
unless item_lua.is_value
- line, src = item.source\get_line!, item.source\get_text!
- error "#{line}: Cannot use #{colored.yellow src} as a list item, since it's not an expression.", 0
+ error "Cannot use #{colored.yellow repr(item)} as a list item, since it's not an expression.", 0
lua\append item_lua
item_string = tostring(item_lua)
last_line = item_string\match("[^\n]*$")
@@ -285,7 +292,7 @@ Tree "List",
line_length = #last_line
else
line_length += #last_line
- if i < #@value
+ if i < #@
if line_length >= MAX_LINE
lua\append ",\n "
line_length = 0
@@ -297,8 +304,8 @@ Tree "List",
as_nomsu: (inline=false)=>
if inline
- nomsu = Nomsu(@source, "[")
- for i, item in ipairs @value
+ nomsu = Nomsu(nil, "[")
+ for i, item in ipairs @
item_nomsu = item\as_nomsu(true)
return nil unless item_nomsu
if i > 1
@@ -310,9 +317,9 @@ Tree "List",
inline_version = @as_nomsu(true)
if inline_version and #inline_version <= MAX_LINE
return inline_version
- nomsu = Nomsu(@source, "[..]")
- line = Nomsu(@source, "\n ")
- for item in *@value
+ nomsu = Nomsu(nil, "[..]")
+ line = Nomsu(nil, "\n ")
+ for item in *@
item_nomsu = item\as_nomsu(true)
if item_nomsu and #line + #", " + #item_nomsu <= MAX_LINE
if #line.bits > 1
@@ -324,17 +331,17 @@ Tree "List",
return nil unless item_nomsu
if #line.bits > 1
nomsu\append line
- line = Nomsu(item.source, "\n ")
+ line = Nomsu(nil, "\n ")
line\append item_nomsu
if #line.bits > 1
nomsu\append line
return nomsu
-Tree "Dict",
+Tree "Dict", 'multi',
as_lua: (nomsu)=>
- lua = Lua.Value @source, "{"
+ lua = Lua.Value nil, "{"
line_length = 0
- for i, entry in ipairs @value
+ for i, entry in ipairs @
entry_lua = entry\as_lua(nomsu)
lua\append entry_lua
entry_lua_str = tostring(entry_lua)
@@ -344,7 +351,7 @@ Tree "Dict",
line_length = #last_line
else
line_length += #entry_lua_str
- if i < #@value
+ if i < #@
if line_length >= MAX_LINE
lua\append ",\n "
line_length = 0
@@ -356,8 +363,8 @@ Tree "Dict",
as_nomsu: (inline=false)=>
if inline
- nomsu = Nomsu(@source, "{")
- for i, entry in ipairs @value
+ nomsu = Nomsu(nil, "{")
+ for i, entry in ipairs @
entry_nomsu = entry\as_nomsu(true)
return nil unless entry_nomsu
if i > 1
@@ -368,9 +375,9 @@ Tree "Dict",
else
inline_version = @as_nomsu(true)
if inline_version then return inline_version
- nomsu = Nomsu(@source, "{..}")
- line = Nomsu(@source, "\n ")
- for entry in *@value
+ nomsu = Nomsu(nil, "{..}")
+ line = Nomsu(nil, "\n ")
+ for entry in *@
entry_nomsu = entry\as_nomsu!
return nil unless entry_nomsu
if #line + #tostring(entry_nomsu) <= MAX_LINE
@@ -380,82 +387,78 @@ Tree "Dict",
else
if #line.bits > 1
nomsu\append line
- line = Nomsu(bit.source, "\n ")
+ line = Nomsu(nil, "\n ")
line\append entry_nomsu
if #line.bits > 1
nomsu\append line
return nomsu
-Tree "DictEntry",
+Tree "DictEntry", 'multi',
as_lua: (nomsu)=>
- key, value = @value[1], @value[2]
+ key, value = @[1], @[2]
key_lua = key\as_lua(nomsu)
unless key_lua.is_value
- line, src = key.source\get_line!, key.source\get_text!
- error "#{line}: Cannot use #{colored.yellow src} as a dict key, since it's not an expression.", 0
- value_lua = value and value\as_lua(nomsu) or Lua.Value(key.source, "true")
+ error "Cannot use #{colored.yellow repr(key)} as a dict key, since it's not an expression.", 0
+ value_lua = value and value\as_lua(nomsu) or Lua.Value(nil, "true")
unless value_lua.is_value
- line, src = value.source\get_line!, value.source\get_text!
- error "#{line}: Cannot use #{colored.yellow src} as a dict value, since it's not an expression.", 0
+ error "Cannot use #{colored.yellow repr(value)} as a dict value, since it's not an expression.", 0
key_str = tostring(key_lua)\match([=[["']([a-zA-Z_][a-zA-Z0-9_]*)['"]]=])
return if key_str
- Lua key.source, key_str,"=",value_lua
+ Lua nil, key_str,"=",value_lua
elseif tostring(key_lua)\sub(1,1) == "["
-- NOTE: this *must* use a space after the [ to avoid freaking out
-- Lua's parser if the inner expression is a long string. Lua
-- parses x[[[y]]] as x("[y]"), not as x["y"]
- Lua key.source, "[ ",key_lua,"]=",value_lua
+ Lua nil, "[ ",key_lua,"]=",value_lua
else
- Lua key.source, "[",key_lua,"]=",value_lua
+ Lua nil, "[",key_lua,"]=",value_lua
as_nomsu: (inline=true)=>
- key, value = @value[1], @value[2]
+ key, value = @[1], @[2]
key_nomsu = key\as_nomsu(true)
return nil unless key_nomsu
if key.type == "Action" or key.type == "Block"
key_nomsu\parenthesize!
value_nomsu = if value
value\as_nomsu(true)
- else Nomsu(key.source, "")
+ else Nomsu(nil, "")
if inline and not value_nomsu then return nil
if not value_nomsu
return nil if inline
value_nomsu = value\as_nomsu!
return nil unless value_nomsu
- return Nomsu key.source, key_nomsu, ":", value_nomsu
+ return Nomsu nil, key_nomsu, ":", value_nomsu
-Tree "IndexChain",
+Tree "IndexChain", 'multi',
as_lua: (nomsu)=>
- lua = @value[1]\as_lua(nomsu)
+ lua = @[1]\as_lua(nomsu)
unless lua.is_value
- line, src = @value[1].source\get_line!, @value[1].source\get_text!
- error "#{line}: Cannot index #{colored.yellow src}, since it's not an expression.", 0
+ error "Cannot index #{colored.yellow repr(@[1])}, since it's not an expression.", 0
first_char = tostring(lua)\sub(1,1)
if first_char == "{" or first_char == '"' or first_char == "["
lua\parenthesize!
- for i=2,#@value
- key = @value[i]
- if key.type == 'Text' and #key.value == 1 and type(key.value[1]) == 'string' and key.value[1]\match("^[a-zA-Z_][a-zA-Z0-9_]*$")
- lua\append ".#{key.value[1]}"
- continue
+ for i=2,#@
+ key = @[i]
key_lua = key\as_lua(nomsu)
unless key_lua.is_value
- line, src = key.source\get_line!, key.source\get_text!
- error "#{line}: Cannot use #{colored.yellow src} as an index, since it's not an expression.", 0
- -- NOTE: this *must* use a space after the [ to avoid freaking out
- -- Lua's parser if the inner expression is a long string. Lua
- -- parses x[[[y]]] as x("[y]"), not as x["y"]
- if tostring(key_lua)\sub(1,1) == '['
- lua\append "[ ",key_lua,"]"
+ error "Cannot use #{colored.yellow repr(key)} as an index, since it's not an expression.", 0
+ key_lua_str = tostring(key_lua)
+ if lua_id = key_lua_str\match("^['\"]([a-zA-Z_][a-zA-Z0-9_]*)['\"]$")
+ lua\append ".#{lua_id}"
+ elseif key_lua_str\sub(1,1) == '['
+ -- NOTE: this *must* use a space after the [ to avoid freaking out
+ -- Lua's parser if the inner expression is a long string. Lua
+ -- parses x[[[y]]] as x("[y]"), not as x["y"]
+ lua\append "[ ",key_lua," ]"
else
lua\append "[",key_lua,"]"
return lua
as_nomsu: (inline=false)=>
- nomsu = Nomsu(@source)
- for i, bit in ipairs @value
+ nomsu = Nomsu!
+ for i, bit in ipairs @
if i > 1
nomsu\append "."
bit_nomsu = bit\as_nomsu(true)
@@ -465,39 +468,39 @@ Tree "IndexChain",
nomsu\append bit_nomsu
return nomsu
-Tree "Number",
+Tree "Number", 'single',
as_lua: (nomsu)=>
- Lua.Value(@source, tostring(@value))
+ Lua.Value(nil, tostring(@value))
as_nomsu: (inline=false)=>
- return Nomsu(@source, tostring(@value))
+ return Nomsu(nil, tostring(@value))
-Tree "Var",
+Tree "Var", 'single',
as_lua_id: (v)->
"_"..(v\gsub("%W", (c)-> if c == "_" then "__" else ("_%x")\format(c\byte!)))
as_lua: (nomsu)=>
- Lua.Value(@source, self.as_lua_id(@value))
+ Lua.Value(nil, self.as_lua_id(@value))
as_nomsu: (inline=false)=>
- return Nomsu(@source, "%", @value)
+ return Nomsu(nil, "%", @value)
-Tree "Word",
+Tree "Word", 'single',
as_lua: (nomsu)=>
error("Attempt to convert Word to lua")
as_nomsu: (inline=false)=>
- return Nomsu(@source, @value)
+ return Nomsu(nil, @value)
-Tree "Comment",
+Tree "Comment", 'single',
as_lua: (nomsu)=>
- Lua(@source, "--"..@value\gsub("\n","\n--").."\n")
+ Lua(nil, "--"..@value\gsub("\n","\n--").."\n")
as_nomsu: (inline=false)=>
return nil if inline
if @value\match("\n")
- return Nomsu(@source, "#..", @value\gsub("\n", "\n "))
+ return Nomsu(nil, "#..", @value\gsub("\n", "\n "))
else
- return Nomsu(@source, "#", @value)
+ return Nomsu(nil, "#", @value)
return Types