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
|
local lpeg = require('lpeg')
local re = require('re')
local files = { }
local _FILE_CACHE = { }
files.spoof = function(filename, contents)
_FILE_CACHE[filename] = contents
end
files.read = function(filename)
do
local file_contents = _FILE_CACHE[filename]
if file_contents then
return file_contents
end
end
if filename == 'stdin' then
local contents = io.read('*a')
_FILE_CACHE['stdin'] = contents
return contents
end
local file = io.open(filename)
if package.nomsupath and not file then
for nomsupath in package.nomsupath:gmatch("[^;]+") do
file = io.open(nomsupath .. "/" .. filename)
if file then
break
end
end
end
if not (file) then
return nil
end
local contents = file:read("*a")
file:close()
_FILE_CACHE[filename] = contents
return contents
end
local iterate_single
iterate_single = function(item, prev)
if item == prev then
return nil
else
return item
end
end
local match, gsub
do
local _obj_0 = string
match, gsub = _obj_0.match, _obj_0.gsub
end
iterate_single = function(item, prev)
if item == prev then
return nil
else
return item
end
end
local ok, lfs = pcall(require, "lfs")
if ok then
local raw_file_exists
raw_file_exists = function(filename)
local mode = lfs.attributes(filename, 'mode')
if mode == 'file' or mode == 'directory' then
return true
else
return false
end
end
files.exists = function(path)
if path == 'stdin' or raw_file_exists(path) then
return true
end
if package.nomsupath then
for nomsupath in package.nomsupath:gmatch("[^;]+") do
if raw_file_exists(nomsupath .. "/" .. path) then
return true
end
end
end
return false
end
local browse
browse = function(filename)
local file_type = lfs.attributes(filename, 'mode')
if file_type == 'file' then
if match(filename, "%.nom$") or match(filename, "%.lua$") then
coroutine.yield(filename)
return true
end
elseif file_type == 'directory' then
for subfile in lfs.dir(filename) do
if not (subfile == "." or subfile == ".." or not subfile:match("%.nom$")) then
browse(filename .. "/" .. subfile)
end
end
return true
elseif file_type == 'char device' then
coroutine.yield(filename)
return true
end
return false
end
files.walk = function(path)
if match(path, "%.nom$") or match(path, "%.lua$") or path == 'stdin' then
return iterate_single, path
end
return coroutine.wrap(function()
if not browse(path) and package.nomsupath then
for nomsupath in package.nomsupath:gmatch("[^;]+") do
if browse(nomsupath .. "/" .. path) then
break
end
end
end
return nil
end)
end
else
if io.popen('find . -maxdepth 0'):close() then
error("Could not find 'luafilesystem' module and couldn't run system command `find` (this might happen on Windows). Please install `luafilesystem` (which can be found at: http://keplerproject.github.io/luafilesystem/ or `luarocks install luafilesystem`)", 0)
end
local sanitize
sanitize = function(path)
path = gsub(path, "\\", "\\\\")
path = gsub(path, "`", "")
path = gsub(path, '"', '\\"')
path = gsub(path, "$", "")
return path
end
files.exists = function(path)
if not (io.popen("ls " .. tostring(sanitize(path))):close()) then
return true
end
if package.nomsupath then
for nomsupath in package.nomsupath:gmatch("[^;]+") do
if not (io.popen("ls " .. tostring(nomsupath) .. "/" .. tostring(sanitize(path))):close()) then
return true
end
end
end
return false
end
files.walk = function(path)
if match(path, "%.nom$") or match(path, "%.lua$") or path == 'stdin' then
return iterate_single, path
end
path = sanitize(path)
return coroutine.wrap(function()
local f = io.popen('find -L "' .. path .. '" -not -path "*/\\.*" -type f -name "*.nom"')
local found = false
for line in f:lines() do
found = true
coroutine.yield(line)
end
if not found and package.nomsupath then
f:close()
for nomsupath in package.nomsupath:gmatch("[^;]+") do
f = io.popen('find -L "' .. package.nomsupath .. '/' .. path .. '" -not -path "*/\\.*" -type f -name "*.nom"')
for line in f:lines() do
found = true
coroutine.yield(line)
end
f:close()
if found then
break
end
end
end
if not (found) then
return error("Invalid file path: " .. tostring(path))
end
end)
end
end
local line_counter = re.compile([[ lines <- {| line (%nl line)* |}
line <- {} (!%nl .)*
]], {
nl = lpeg.P("\r") ^ -1 * lpeg.P("\n")
})
local get_lines = re.compile([[ lines <- {| line (%nl line)* |}
line <- {[^%nl]*}
]], {
nl = lpeg.P("\r") ^ -1 * lpeg.P("\n")
})
local _LINE_STARTS = { }
files.get_line_starts = function(str)
if type(str) ~= 'string' then
str = tostring(str)
end
do
local starts = _LINE_STARTS[str]
if starts then
return starts
end
end
local line_starts = line_counter:match(str)
_LINE_STARTS[str] = line_starts
return line_starts
end
files.get_line_number = function(str, pos)
local line_starts = files.get_line_starts(str)
local lo, hi = 1, #line_starts
while lo <= hi do
local mid = math.floor((lo + hi) / 2)
if line_starts[mid] > pos then
hi = mid - 1
else
lo = mid + 1
end
end
return hi
end
files.get_line = function(str, line_no)
local line_starts = files.get_line_starts(str)
return str:sub(line_starts[line_no] or 1, (line_starts[line_no + 1] or 1) - 2)
end
files.get_lines = function(str)
return get_lines:match(str)
end
return files
|