aboutsummaryrefslogtreecommitdiff
path: root/nomsu_tree.moon
blob: 71bcff99ea55a11fe12bb0eea1e64d6966f83c23 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
-- 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)->
    type(n) == 'table' and getmetatable(n) and AST[n.type] == getmetatable(n)

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 = => "#{@name}(#{concat([repr(v) for v in *@], ', ')})"
        .map = (fn)=>
            if replacement = fn(@) then return replacement
            replacements = [AST.is_syntax_tree(v) and v\map(fn) or nil for v in *@]
            return @ unless next(replacements)
            return (@__class)(@source, unpack([replacements[i] or v for i,v in ipairs(@)]))

    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