aboutsummaryrefslogtreecommitdiff
path: root/nomsu_tree.moon
blob: 2f7c202d4abfb0631d8b2b29e3417a33886f486c (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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
-- This file contains the datastructures used to represent parsed Nomsu syntax trees,
-- as well as the logic for converting them to Lua code.
utils = require 'utils'
{:repr, :stringify, :min, :max, :equivalent, :set, :is_list, :sum} = utils
immutable = require 'immutable'
{:insert, :remove, :concat} = table
{:Lua, :Nomsu, :Location} = require "code_obj"

MAX_LINE = 80 -- For beautification purposes, try not to make lines much longer than this value

Types = {}
Types.is_node = (n)->
    type(n) == 'userdata' and getmetatable(n) and Types[n.type] == getmetatable(n)

-- Helper method:
Tree = (name, kind, methods)->
    methods or= {}
    assert((kind == 'single') or (kind == 'multi'))
    is_multi = (kind == 'multi')
    with methods
        .with_value = (value)=> getmetatable(self)(value)
        .type = name
        .name = name
        .is_multi = is_multi
        .map = (fn)=>
            if type(fn) == 'table'
                return @ unless next(fn)
                if type(next(fn)) == 'string'
                    error("SHIT")
                _replacements = fn
                fn = (k)-> _replacements[k]
            return @_map(fn)
        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 @

    if is_multi
        Types[name] = immutable nil, methods
    else
        Types[name] = immutable {"value"}, methods

Tree "Block", 'multi'
Tree "EscapedNomsu", 'multi'
Tree "Text", 'multi'
Tree "List", 'multi'
Tree "Dict", 'multi'
Tree "DictEntry", 'multi'
Tree "IndexChain", 'multi'
Tree "Number", 'single'
Tree "Word", 'single'
Tree "Comment", 'single'

Tree "Var", 'single',
    as_lua_id: =>
        "_"..(@value\gsub("%W", (c)-> if c == "_" then "__" else ("_%x")\format(c\byte!)))

Tree "Action", 'multi',
    get_stub: (include_names=false)=>
        bits = if include_names
            [(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, " ")

return Types