aboutsummaryrefslogtreecommitdiff
path: root/lua_obj.moon
blob: ef5dc7e25906890d7a5057afe361c834e9c69ec9 (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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
{:insert, :remove, :concat} = table
immutable = require 'immutable'
local Lua, LuaValue, Location
export LINE_STARTS

Location = immutable {"text_name","text","start","stop"}, {
    name:"Location"
    __new: (text_name, text, start, stop)=> text_name, text, start, stop or start
    __tostring: => "#{@text_name}[#{@start}:#{@stop}]"
    __lt: (other)=>
        assert(@text == other.text, "Cannot compare sources from different texts")
        return if @start == other.start
            @stop < other.stop
        else @start < other.start
    __le: (other)=>
        assert(@text == other.text, "Cannot compare sources from different texts")
        return if @start == other.start
            @stop <= other.stop
        else @start <= other.start
    get_text: => @text\sub(@start,@stop)
    get_line_number: =>
        -- TODO: do a binary search if this is actually slow, which I doubt
        line_starts = LINE_STARTS[@text]
        start_line = 1
        while (line_starts[start_line+1] or (#src+1)) <= @start
            start_line += 1
        stop_line = start_line
        while (line_starts[stop_line+1] or (#src+1)) <= @stop
            stop_line += 1
        return start_line, stop_line
    get_line: => "#{@text_name}:#{@get_line_number}"
    get_line_range: =>
        start_line, stop_line = @get_line_number
        return if stop_line == start_line
            "#{text_name}:#{start_line}"
        else "#{text_name}:#{start_line}-#{stop_line}"
}

class Lua
    is_statement: true
    is_value: false

    new: (@source, ...)=>
        @bits = {...}
        @free_vars = {}
    
    add_free_vars: (free_vars)=>
        seen = {[v]:true for v in *@free_vars}
        for var in *free_vars
            unless seen[var]
                @free_vars[#@free_vars+1] = var
                seen[var] = true

    as_statements: => self

    declare_locals: (skip={})=>
        if next(skip) == 1
            skip = {[s]:true for s in *skip}
        if #@free_vars > 0
            @prepend "local #{concat @free_vars, ", "};\n"
        for var in *@free_vars do skip[var] = true
        for bit in *@bits
            if type(bit) == Lua
                bit\declare_locals(skip)

    __tostring: =>
        buff = {}
        for b in *@bits
            buff[#buff+1] = tostring(b)
        ret = concat(buff, "")
        assert(not ret\match(".*table: 0x.*"))
        return ret

    __len: =>
        len = 0
        for b in *@bits
            len += #b
        return len
    
    append: (...)=>
        n = select("#",...)
        bits = @bits
        for i=1,n
            bits[#bits+1] = select(i, ...)
    
    prepend: (...)=>
        n = select("#",...)
        bits = @bits
        for i=#bits+n,n+1,-1
            bits[i] = bits[i-n]
        for i=1,n
            bits[i] = select(i, ...)

    make_offset_table: (lua_chunkname)=>
        -- Return a mapping from output (lua) character number to input (nomsu) character number
        lua_str = tostring(self)
        metadata = {
            nomsu_filename:@source.text_name, nomsu_file:@source.text,
            lua_filename:lua_chunkname, lua_file:lua_str
            lua_to_nomsu: {}, nomsu_to_lua: {}
        }
        lua_offset = 1
        walk = (lua)->
            if type(lua) == 'string'
                lua_offset += #lua
            else
                lua_start = lua_offset
                for b in *lua.bits
                    walk b
                lua_stop = lua_offset
                nomsu_src, lua_src = lua.source, Location(lua_chunkname, lua_str, lua_start, lua_stop)
                metadata.lua_to_nomsu[lua_src] = nomsu_src
                metadata.nomsu_to_lua[nomsu_src] = lua_src
        walk self
        return lua_str, metadata

class LuaValue extends Lua
    is_statement: false
    is_value: true

    new: (@source, ...)=>
        @bits = {...}

    __tostring: =>
        buff = {}
        for b in *@bits
            buff[#buff+1] = tostring(b)
        ret = concat(buff, "")
        assert(not ret\match(".*table: 0x.*"))
        return ret

    as_statements: =>
        bits = {unpack @bits}
        bits[#bits+1] = ";"
        return Lua(@source, bits)

    parenthesize: =>
        @prepend "("
        @append ")"

return {:Lua, :LuaValue, :Location}