aboutsummaryrefslogtreecommitdiff
path: root/code_obj.lua
blob: 470cd1182d884c265430299fb964aeccf2bd1fc7 (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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
local insert, remove, concat
do
  local _obj_0 = table
  insert, remove, concat = _obj_0.insert, _obj_0.remove, _obj_0.concat
end
local repr
repr = require('utils').repr
local LuaCode, NomsuCode, Source
do
  local _class_0
  local _base_0 = {
    __tostring = function(self)
      if self.stop then
        return "@" .. tostring(self.filename) .. "[" .. tostring(self.start) .. ":" .. tostring(self.stop) .. "]"
      else
        return "@" .. tostring(self.filename) .. "[" .. tostring(self.start) .. "]"
      end
    end,
    __eq = function(self, other)
      return getmetatable(self) == getmetatable(other) and self.filename == other.filename and self.start == other.start and self.stop == other.stop
    end,
    __lt = function(self, other)
      assert(self.filename == other.filename, "Cannot compare sources from different files")
      if self.start == other.start then
        return (self.stop or self.start) < (other.stop or other.start)
      else
        return self.start < other.start
      end
    end,
    __le = function(self, other)
      assert(self.filename == other.filename, "Cannot compare sources from different files")
      if self.start == other.start then
        return (self.stop or self.start) <= (other.stop or other.start)
      else
        return self.start <= other.start
      end
    end,
    __add = function(self, offset)
      if type(self) == 'number' then
        offset, self = self, offset
      else
        if type(offset) ~= 'number' then
          error("Cannot add Source and " .. tostring(type(offset)))
        end
      end
      return Source(self.filename, self.start + offset, self.stop)
    end
  }
  _base_0.__index = _base_0
  _class_0 = setmetatable({
    __init = function(self, filename, start, stop)
      self.filename, self.start, self.stop = filename, start, stop
    end,
    __base = _base_0,
    __name = "Source"
  }, {
    __index = _base_0,
    __call = function(cls, ...)
      local _self_0 = setmetatable({}, _base_0)
      cls.__init(_self_0, ...)
      return _self_0
    end
  })
  _base_0.__class = _class_0
  local self = _class_0
  self.from_string = function(self, str)
    local filename, start, stop = str:match("^@(.-)%[(%d+):(%d+)%]$")
    if not (filename) then
      filename, start = str:match("^@(.-)%[(%d+)%]$")
    end
    return self(filename or str, tonumber(start or 1), tonumber(stop))
  end
  self.is_instance = function(self, x)
    return type(x) == 'table' and x.__class == self
  end
  Source = _class_0
end
local Code
do
  local _class_0
  local _base_0 = {
    is_code = true,
    dirty = function(self)
      self.__str = nil
      self._trailing_line_len = nil
      self._is_multiline = nil
    end,
    append = function(self, ...)
      local n = select("#", ...)
      local match = string.match
      local bits = self.bits
      for i = 1, n do
        local _continue_0 = false
        repeat
          local b = select(i, ...)
          assert(b, "code bit is nil")
          assert(not Source:is_instance(b), "code bit is a Source")
          if b == '' then
            _continue_0 = true
            break
          end
          bits[#bits + 1] = b
          if type(b) ~= 'string' and not (type(b) == 'table' and b.is_code) then
            b = repr(b)
          end
          _continue_0 = true
        until true
        if not _continue_0 then
          break
        end
      end
      return self:dirty()
    end,
    trailing_line_len = function(self)
      if self._trailing_line_len == nil then
        local bits, match = self.bits, string.match
        local len = 0
        for i = #bits, 1, -1 do
          local b = bits[i]
          if type(b) == 'string' then
            do
              local line = match(b, "\n([^\n]*)$")
              if line then
                len = len + #line
                break
              else
                len = len + #b
              end
            end
          else
            len = len + b:trailing_line_len()
            if b:is_multiline() then
              break
            end
          end
        end
        self._trailing_line_len = len
      end
      return self._trailing_line_len
    end,
    is_multiline = function(self)
      if self._is_multiline == nil then
        local match = string.match
        self._is_multiline = false
        local _list_0 = self.bits
        for _index_0 = 1, #_list_0 do
          local b = _list_0[_index_0]
          if type(b) ~= 'string' or match(b, "\n") then
            self._is_multiline = true
            break
          end
        end
      end
      return self._is_multiline
    end,
    concat_append = function(self, values, joiner, wrapping_joiner)
      wrapping_joiner = wrapping_joiner or joiner
      local match = string.match
      local bits = self.bits
      local line_len = 0
      for i = 1, #values do
        local b = values[i]
        if i > 1 then
          if line_len > 80 then
            bits[#bits + 1] = wrapping_joiner
            line_len = 0
          else
            bits[#bits + 1] = joiner
          end
        end
        bits[#bits + 1] = b
        local b_str = tostring(b)
        local line = match(b_str, "\n([^\n]*)$")
        if line then
          line_len = #line
        else
          line_len = line_len + #b
        end
      end
      return self:dirty()
    end,
    prepend = function(self, ...)
      local n = select("#", ...)
      local bits = self.bits
      for i = #bits + n, n + 1, -1 do
        bits[i] = bits[i - n]
      end
      for i = 1, n do
        bits[i] = select(i, ...)
      end
      return self:dirty()
    end
  }
  _base_0.__index = _base_0
  _class_0 = setmetatable({
    __init = function(self, source, ...)
      self.source = source
      self.bits = { }
      if type(self.source) == 'string' then
        self.source = Source:from_string(self.source)
      end
      assert(self.source and Source:is_instance(self.source), "Source has the wrong type")
      return self:append(...)
    end,
    __base = _base_0,
    __name = "Code"
  }, {
    __index = _base_0,
    __call = function(cls, ...)
      local _self_0 = setmetatable({}, _base_0)
      cls.__init(_self_0, ...)
      return _self_0
    end
  })
  _base_0.__class = _class_0
  Code = _class_0
end
do
  local _class_0
  local _parent_0 = Code
  local _base_0 = {
    add_free_vars = function(self, vars)
      if not (#vars > 0) then
        return 
      end
      local seen
      do
        local _tbl_0 = { }
        local _list_0 = self.free_vars
        for _index_0 = 1, #_list_0 do
          local v = _list_0[_index_0]
          local _key_0, _val_0 = {
            [v] = true
          }
          _tbl_0[_key_0] = _val_0
        end
        seen = _tbl_0
      end
      for _index_0 = 1, #vars do
        local var = vars[_index_0]
        assert(type(var) == 'string')
        if not (seen[var]) then
          self.free_vars[#self.free_vars + 1] = var
          seen[var] = true
        end
      end
      return self:dirty()
    end,
    remove_free_vars = function(self, vars)
      if not (#vars > 0) then
        return 
      end
      local removals = { }
      for _index_0 = 1, #vars do
        local var = vars[_index_0]
        assert(type(var) == 'string')
        removals[var] = true
      end
      local stack = {
        self
      }
      while #stack > 0 do
        local lua
        lua, stack[#stack] = stack[#stack], nil
        for i = #lua.free_vars, 1, -1 do
          local free_var = lua.free_vars[i]
          if removals[free_var] then
            remove(lua.free_vars, i)
          end
        end
        local _list_0 = lua.bits
        for _index_0 = 1, #_list_0 do
          local b = _list_0[_index_0]
          if type(b) ~= 'string' then
            stack[#stack + 1] = b
          end
        end
      end
      return self:dirty()
    end,
    declare_locals = function(self, to_declare)
      if to_declare == nil then
        to_declare = nil
      end
      if to_declare == nil then
        local seen
        to_declare, seen = { }, { }
        local gather_from
        gather_from = function(self)
          local _list_0 = self.free_vars
          for _index_0 = 1, #_list_0 do
            local var = _list_0[_index_0]
            if not (seen[var]) then
              seen[var] = true
              to_declare[#to_declare + 1] = var
            end
          end
          local _list_1 = self.bits
          for _index_0 = 1, #_list_1 do
            local bit = _list_1[_index_0]
            if bit.__class == LuaCode then
              gather_from(bit)
            end
          end
        end
        gather_from(self)
      end
      if #to_declare > 0 then
        self:remove_free_vars(to_declare)
        self:prepend("local " .. tostring(concat(to_declare, ", ")) .. ";\n")
      end
      return to_declare
    end,
    as_statements = function(self, prefix, suffix)
      if prefix == nil then
        prefix = ""
      end
      if suffix == nil then
        suffix = ";"
      end
      if not (self.is_value) then
        return self
      end
      local statements = LuaCode(self.source)
      if prefix ~= "" then
        statements:append(prefix)
      end
      statements:append(self)
      if suffix ~= "" then
        statements:append(suffix)
      end
      return statements
    end,
    __tostring = function(self)
      if self.__str == nil then
        local buff, indent = { }, 0
        local match, gsub, rep
        do
          local _obj_0 = string
          match, gsub, rep = _obj_0.match, _obj_0.gsub, _obj_0.rep
        end
        for i, b in ipairs(self.bits) do
          if type(b) == 'string' then
            do
              local spaces = match(b, "\n([ ]*)[^\n]*$")
              if spaces then
                indent = #spaces
              end
            end
          else
            b = tostring(b)
            if indent > 0 then
              b = gsub(b, "\n", "\n" .. rep(" ", indent))
            end
          end
          buff[#buff + 1] = b
        end
        self.__str = concat(buff, "")
      end
      return self.__str
    end,
    __len = function(self)
      return #tostring(self)
    end,
    make_offset_table = function(self)
      local lua_to_nomsu, nomsu_to_lua = { }, { }
      local walk
      walk = function(lua, pos)
        local _list_0 = lua.bits
        for _index_0 = 1, #_list_0 do
          local b = _list_0[_index_0]
          if type(b) == 'string' then
            if lua.source then
              lua_to_nomsu[pos] = lua.source.start
              nomsu_to_lua[lua.source.start] = pos
            end
          else
            walk(b, pos)
          end
          pos = pos + #tostring(b)
        end
      end
      walk(self, 1)
      return {
        nomsu_filename = self.source.filename,
        lua_filename = tostring(self.source) .. ".lua",
        lua_file = self:stringify(),
        lua_to_nomsu = lua_to_nomsu,
        nomsu_to_lua = nomsu_to_lua
      }
    end,
    parenthesize = function(self)
      if self.is_value then
        self:prepend("(")
        return self:append(")")
      else
        return error("Cannot parenthesize lua statements")
      end
    end
  }
  _base_0.__index = _base_0
  setmetatable(_base_0, _parent_0.__base)
  _class_0 = setmetatable({
    __init = function(self, ...)
      _class_0.__parent.__init(self, ...)
      self.free_vars = { }
      self.is_value = false
    end,
    __base = _base_0,
    __name = "LuaCode",
    __parent = _parent_0
  }, {
    __index = function(cls, name)
      local val = rawget(_base_0, name)
      if val == nil then
        local parent = rawget(cls, "__parent")
        if parent then
          return parent[name]
        end
      else
        return val
      end
    end,
    __call = function(cls, ...)
      local _self_0 = setmetatable({}, _base_0)
      cls.__init(_self_0, ...)
      return _self_0
    end
  })
  _base_0.__class = _class_0
  local self = _class_0
  self.Value = function(...)
    local lua = LuaCode(...)
    lua.is_value = true
    return lua
  end
  if _parent_0.__inherited then
    _parent_0.__inherited(_parent_0, _class_0)
  end
  LuaCode = _class_0
end
do
  local _class_0
  local _parent_0 = Code
  local _base_0 = {
    __tostring = function(self)
      if self.__str == nil then
        local buff, indent = { }, 0
        local match, gsub, rep
        do
          local _obj_0 = string
          match, gsub, rep = _obj_0.match, _obj_0.gsub, _obj_0.rep
        end
        for i, b in ipairs(self.bits) do
          if type(b) == 'string' then
            do
              local spaces = match(b, "\n([ ]*)[^\n]*$")
              if spaces then
                indent = #spaces
              end
            end
          else
            b = tostring(b)
            if indent > 0 then
              b = gsub(b, "\n", "\n" .. rep(" ", indent))
            end
          end
          buff[#buff + 1] = b
        end
        self.__str = concat(buff, "")
      end
      return self.__str
    end,
    __len = function(self)
      return #tostring(self)
    end,
    parenthesize = function(self)
      self:prepend("(")
      return self:append(")")
    end
  }
  _base_0.__index = _base_0
  setmetatable(_base_0, _parent_0.__base)
  _class_0 = setmetatable({
    __init = function(self, ...)
      return _class_0.__parent.__init(self, ...)
    end,
    __base = _base_0,
    __name = "NomsuCode",
    __parent = _parent_0
  }, {
    __index = function(cls, name)
      local val = rawget(_base_0, name)
      if val == nil then
        local parent = rawget(cls, "__parent")
        if parent then
          return parent[name]
        end
      else
        return val
      end
    end,
    __call = function(cls, ...)
      local _self_0 = setmetatable({}, _base_0)
      cls.__init(_self_0, ...)
      return _self_0
    end
  })
  _base_0.__class = _class_0
  if _parent_0.__inherited then
    _parent_0.__inherited(_parent_0, _class_0)
  end
  NomsuCode = _class_0
end
return {
  Code = Code,
  NomsuCode = NomsuCode,
  LuaCode = LuaCode,
  Source = Source
}