diff options
| author | Bruce Hill <bitbucket@bruce-hill.com> | 2018-05-16 18:12:56 -0700 |
|---|---|---|
| committer | Bruce Hill <bitbucket@bruce-hill.com> | 2018-05-16 18:13:02 -0700 |
| commit | 6f6c4377b236902566794c3d06820f3fdd7ec28c (patch) | |
| tree | a3074d4d7c46585a9ece036455ff97b9ab12effc /nomsu_tree.moon | |
| parent | af9dc0702568dc45b8809523dde760bb99aafbcb (diff) | |
Initial working version.
Diffstat (limited to 'nomsu_tree.moon')
| -rw-r--r-- | nomsu_tree.moon | 253 |
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 |
