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
|
{:insert, :remove, :concat} = table
immutable = require 'immutable'
local Lua, LuaValue, Location
Location = immutable {"text_name","text","start","stop"}, {
__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 start_line < #line_starts and line_starts[start_line+1] <= @start
start_line += 1
stop_line = start_line
while stop_line < #line_starts and line_starts[stop_line+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}
@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
if type(b) == 'string'
buff[#buff+1] = b
else
for sub in *b\render!
buff[#buff+1] = sub
return concat(buff, "")
__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: {}
}
metadata, lua_offset = {}, 1
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.souce, 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 = {...}
as_statements: =>
bits = {unpack @bits}
bits[#bits+1] = ";"
return Lua(@source, bits)
parenthesize: =>
@prepend "("
@append ")"
return {:Lua, :LuaValue}
|