nomsu/nomsu_tree.moon
Bruce Hill be06fc096a Major changes to how versioning and parsing work. This should be a
better path going forward to handling upgrades. Old syntax files will
stick around for compatibility purposes. Old syntax can be parsed into
valid syntax trees via the old syntax (.peg) files, and then old syntax
trees should be valid and can be upgraded via the normal code path. This
change has lots of improvements to Nomsu codegen too.
2018-07-15 19:43:28 -07:00

57 lines
1.9 KiB
Plaintext

-- This file contains the datastructures used to represent parsed Nomsu syntax trees,
-- as well as the logic for converting them to Lua code.
{:repr} = require 'utils'
{:insert, :remove, :concat} = table
{:Source} = require "code_obj"
unpack or= table.unpack
AST = {}
AST.is_syntax_tree = (n, t=nil)->
type(n) == 'table' and getmetatable(n) and AST[n.type] == getmetatable(n) and (t == nil or n.type == t)
types = {"Number", "Var", "Block", "EscapedNomsu", "Text", "List", "Dict", "DictEntry",
"IndexChain", "Action", "FileChunks"}
for name in *types
cls = {}
with cls
.__class = cls
.__index = cls
.__name = name
.type = name
.is_instance = (x)=> getmetatable(x) == @
.__tostring = => "#{@type}(#{repr tostring(@source)}, #{concat([repr(v) for v in *@], ', ')})"
.map = (fn)=>
replacement = fn(@)
if replacement != nil then return replacement or nil
replacements = {}
changes = false
for i,v in ipairs(@)
replacement = if AST.is_syntax_tree(v)
v\map(fn)
else v
changes or= replacement != v
replacements[#replacements+1] = replacement
return @ unless changes
return (@__class)(@source, unpack(replacements))
AST[name] = setmetatable cls,
__tostring: => @name
__call: (source, ...)=>
if type(source) == 'string'
source = Source\from_string(source)
for i=1,select('#', ...) do assert(select(i,...))
assert(Source\is_instance(source))
inst = {:source, ...}
setmetatable(inst, @)
if inst.__init then inst\__init!
return inst
AST.Action.__init = =>
stub_bits = [type(a) == 'string' and a or '%' for a in *@]
@stub = concat stub_bits, " "
AST.Action.get_args = =>
[tok for tok in *@ when type(tok) != 'string']
return AST