Differences From
Artifact [ce122c09dc]:
2 2
3 3 local util = dofile('common.lua')
4 4 local buildopts, buildargs = util.parseargs{...}
5 5 config = dofile('config.lua')
6 6
7 7 lib = {
8 8 init = {};
9 + load = function(lst)
10 + for _, l in pairs(lst) do
11 + lib[l] = terralib.loadfile(l .. '.t')()
12 + end
13 + end;
9 14 loadlib = function(name,hdr)
10 15 local p = config.pkg[name]
11 16 -- for _,v in pairs(p.dylibs) do
12 17 -- terralib.linklibrary(p.libdir .. '/' .. v)
13 18 -- end
14 19 return terralib.includec(p.incdir .. '/' .. hdr)
15 20 end;
................................................................................
17 22 return macro(function(v,...)
18 23 for ty,fn in pairs(tbl) do
19 24 if v.tree.type == ty then return fn(v,...) end
20 25 end
21 26 return (tbl[false])(v,...)
22 27 end)
23 28 end;
24 - emit = function(...)
29 + emit_unitary = function(fd,...)
25 30 local code = {}
26 31 for i,v in ipairs{...} do
27 32 if type(v) == 'string' or type(v) == 'number' then
28 33 local str = tostring(v)
29 34 code[#code+1] = `lib.io.send(2, str, [#str])
35 + elseif type(v) == 'table' and #v == 2 then
36 + code[#code+1] = `lib.io.send(2, [v[1]], [v[2]])
30 37 elseif v.tree:is 'constant' then
31 38 local str = tostring(v:asvalue())
32 39 code[#code+1] = `lib.io.send(2, str, [#str])
33 40 else
34 41 code[#code+1] = quote var n = v in
35 42 lib.io.send(2, n, lib.str.sz(n)) end
36 43 end
37 44 end
38 - code[#code+1] = `lib.io.send(2, '\n', 1)
45 + code[#code+1] = `lib.io.send(fd, '\n', 1)
39 46 return code
40 47 end;
48 + emitv = function(fd,...)
49 + local vec = {}
50 + local defs = {}
51 + for i,v in ipairs{...} do
52 + local str, ct
53 + if type(v) == 'table' and v.tree and not (v.tree:is 'constant') then
54 + if v.tree.type.convertible == 'tuple' then
55 + str = `v._0
56 + ct = `v._1
57 + else
58 + local n = symbol(v.tree.type)
59 + defs[#defs + 1] = quote var [n] = v end
60 + str = n
61 + ct = `lib.str.sz(n)
62 + end
63 + else
64 + if type(v) == 'string' or type(v) == 'number' then
65 + str = tostring(v)
66 + else--if v.tree:is 'constant' then
67 + str = tostring(v:asvalue())
68 + end
69 + ct = ct or #str
70 + end
71 + vec[#vec + 1] = `[lib.uio.iovec]{iov_base = [&opaque](str), iov_len = ct}
72 + end
73 + vec[#vec + 1] = `[lib.uio.iovec]{iov_base = [&opaque]('\n'), iov_len = 1}
74 + return quote
75 + [defs]
76 + var strs = array( [vec] )
77 + in lib.uio.writev(fd, strs, [#vec]) end
78 + end;
41 79 trn = macro(function(cond, i, e)
42 80 return quote
43 81 var c: bool = [cond]
44 82 var r: i.tree.type
45 83 if c == true then r = i else r = e end
46 84 in r end
47 85 end);
................................................................................
52 90 io = {
53 91 send = terralib.externfunction('write', {int, rawstring, intptr} -> ptrdiff);
54 92 recv = terralib.externfunction('read', {int, rawstring, intptr} -> ptrdiff);
55 93 say = macro(function(msg) return `lib.io.send(2, msg, [#(msg:asvalue())]) end);
56 94 fmt = terralib.externfunction('printf',
57 95 terralib.types.funcpointer({rawstring},{int},true));
58 96 };
59 - str = {
60 - sz = terralib.externfunction('strlen', rawstring -> intptr);
61 - cmp = terralib.externfunction('strcmp', {rawstring, rawstring} -> int);
62 - ncmp = terralib.externfunction('strncmp', {rawstring, rawstring, intptr} -> int);
63 - cpy = terralib.externfunction('stpcpy',{rawstring, rawstring} -> rawstring);
64 - ncpy = terralib.externfunction('stpncpy',{rawstring, rawstring, intptr} -> rawstring);
65 - ndup = terralib.externfunction('strndup',{rawstring, intptr} -> rawstring);
66 - fmt = terralib.externfunction('asprintf',
67 - terralib.types.funcpointer({&rawstring},{int},true));
68 - };
97 + str = { sz = terralib.externfunction('strlen', rawstring -> intptr) };
69 98 copy = function(tbl)
70 99 local new = {}
71 100 for k,v in pairs(tbl) do new[k] = v end
72 101 setmetatable(new, getmetatable(tbl))
73 102 return new
74 103 end;
75 - mem = {
76 - zero = macro(function(r)
77 - return quote
78 - for i = 0, [r.tree.type.N] do r[i] = 0 end
79 - end
80 - end);
81 - heapa_raw = terralib.externfunction('malloc', intptr -> &opaque);
82 - heapr_raw = terralib.externfunction('realloc', {&opaque, intptr} -> &opaque);
83 - heapf = terralib.externfunction('free', &opaque -> {});
84 - cpy = terralib.externfunction('mempcpy',{&opaque, &opaque, intptr} -> &opaque);
85 - heapa = macro(function(ty, sz)
86 - local p = lib.mem.ptr(ty:astype())
87 - return `p {
88 - ptr = [&ty:astype()](lib.mem.heapa_raw(sizeof(ty) * sz));
89 - ct = sz;
90 - }
91 - end)
92 - };
93 104 }
105 +if config.posix then
106 + lib.uio = terralib.includec 'sys/uio.h';
107 + lib.emit = lib.emitv -- use more efficient call where available
108 +else lib.emit = lib.emit_unitary end
94 109
95 110 local noise = global(uint8,1)
96 111 local noise_header = function(code,txt,mod)
97 112 if mod then
98 113 return string.format('\27[%s;1m(parsav::%s %s)\27[m ', code,mod,txt)
99 114 else
100 115 return string.format('\27[%s;1m(parsav %s)\27[m ', code,txt)
101 116 end
102 117 end
103 118 local defrep = function(level,n,code)
104 119 return macro(function(...)
105 - local q = lib.emit(noise_header(code,n), ...)
120 + local q = lib.emit(2, noise_header(code,n), ...)
106 121 return quote
107 122 if noise >= level then [q] end
108 123 end
109 124 end);
110 125 end
111 126 lib.dbg = defrep(3,'debug', '32')
112 127 lib.report = defrep(2,'info', '35')
113 128 lib.warn = defrep(1,'warn', '33')
114 129 lib.bail = macro(function(...)
115 - local q = lib.emit(noise_header('31','fatal'), ...)
130 + local q = lib.emit(2, noise_header('31','fatal'), ...)
116 131 return quote
117 132 [q]
118 133 lib.proc.exit(1)
119 134 end
120 135 end);
121 136 lib.stat = terralib.memoize(function(ty)
122 137 local n = struct {
................................................................................
137 152 elseif #tbl >= 2^8 then ty = uint16 end
138 153 local o = { t = ty }
139 154 for i, name in ipairs(tbl) do
140 155 o[name] = i
141 156 end
142 157 return o
143 158 end
144 -lib.mem.ptr = terralib.memoize(function(ty)
145 - local t = terralib.types.newstruct(string.format('ptr<%s>', ty))
146 - t.entries = {
147 - {'ptr', &ty};
148 - {'ct', intptr};
149 - }
150 - t.ptr_basetype = ty
151 - local recurse = false
152 - if ty:isstruct() then
153 - if ty.methods.free then recurse = true end
154 - end
155 - t.methods = {
156 - free = terra(self: &t): bool
157 - [recurse and quote
158 - self.ptr:free()
159 - end or {}]
160 - if self.ct > 0 then
161 - lib.mem.heapf(self.ptr)
162 - self.ct = 0
163 - return true
159 +lib.set = function(tbl)
160 + local bytes = math.ceil(#tbl / 8)
161 + local o = {}
162 + for i, name in ipairs(tbl) do o[name] = i end
163 + local struct set { _store: uint8[bytes] }
164 + local struct bit { _v: intptr _set: &set}
165 + terra set:clear() for i=0,bytes do self._store[i] = 0 end end
166 + set.members = tbl
167 + set.name = string.format('set<%s>', table.concat(tbl, '|'))
168 + set.metamethods.__entrymissing = macro(function(val, obj)
169 + if o[val] == nil then error('value ' .. val .. ' not in set') end
170 + return `bit { _v=[o[val] - 1], _set = &obj }
171 + end)
172 + set.methods.dump = macro(function(self)
173 + local q = quote lib.io.say('dumping set:\n') end
174 + for i,v in ipairs(tbl) do
175 + q = quote
176 + [q]
177 + if [bool](self.[v])
178 + then lib.io.say([' - ' .. v .. ': true\n'])
179 + else lib.io.say([' - ' .. v .. ': false\n'])
180 + end
164 181 end
165 - return false
166 - end;
167 - init = terra(self: &t, newct: intptr): bool
168 - var nv = [&ty](lib.mem.heapa_raw(sizeof(ty) * newct))
169 - if nv ~= nil then
170 - self.ptr = nv
171 - self.ct = newct
172 - return true
173 - else return false end
174 - end;
175 - resize = terra(self: &t, newct: intptr): bool
176 - var nv: &ty
177 - if self.ct > 0
178 - then nv = [&ty](lib.mem.heapr_raw(self.ptr, sizeof(ty) * newct))
179 - else nv = [&ty](lib.mem.heapa_raw(sizeof(ty) * newct))
182 + end
183 + return q
184 + end)
185 + set.metamethods.__add = macro(function(self,other)
186 + local new = symbol(set)
187 + local q = quote var [new] new:clear() end
188 + for i = 0, bytes - 1 do
189 + q = quote [q]
190 + new._store[i] = self._store[i] or other._store[i]
180 191 end
181 - if nv ~= nil then
182 - self.ptr = nv
183 - self.ct = newct
184 - return true
185 - else return false end
186 - end;
187 - }
188 - return t
189 -end)
190 -lib.mem.vec = terralib.memoize(function(ty)
191 - local v = terralib.types.newstruct(string.format('vec<%s>', ty.name))
192 - v.entries = {
193 - {field = 'storage', type = lib.mem.ptr(ty)};
194 - {field = 'sz', type = intptr};
195 - {field = 'run', type = intptr};
196 - }
197 - local terra biggest(a: intptr, b: intptr)
198 - if a > b then return a else return b end
192 + end
193 + return quote [q] in new end
194 + end)
195 + bit.metamethods.__cast = function(from,to,e)
196 + local q = quote var s = e
197 + in (s._set._store[s._v/8] and (1 << s._v % 8)) end
198 + if to == bit then error('casting to bit is not meaningful')
199 + elseif to == bool then return `([q] ~= 0)
200 + elseif to:isintegral() then return q
201 + elseif from == bit then error('cannot cast bit to ' .. tostring(to))
202 + else return nil end
199 203 end
200 - terra v:assure(n: intptr)
201 - if self.storage.ct < n then
202 - self.storage:resize(biggest(n, self.storage.ct + self.run))
204 + bit.metamethods.__apply = terra(self: &bit): bool return @self end
205 + bit.metamethods.__lshift = terra(self: &bit, hl: bool)
206 + var byte = self._v / 8
207 + var bit = self._v % 8
208 + if hl then
209 + self._set._store[byte] = self._set._store[byte] or (1 << bit)
210 + else
211 + self._set._store[byte] = self._set._store[byte] and not (1 << bit)
203 212 end
204 213 end
205 - v.methods = {
206 - init = terra(self: &v, run: intptr): bool
207 - if not self.storage:init(run) then return false end
208 - self.run = run
209 - self.sz = 0
210 - return true
211 - end;
212 - new = terra(self: &v): &ty
213 - self:assure(self.sz + 1)
214 - self.sz = self.sz + 1
215 - return self.storage.ptr + (self.sz - 1)
216 - end;
217 - push = terra(self: &v, val: ty)
218 - self:assure(self.sz + 1)
219 - self.storage.ptr[self.sz] = val
220 - self.sz = self.sz + 1
221 - end;
222 - free = terra(self: &v) self.storage:free() end;
223 - last = terra(self: &v, idx: intptr): &ty
224 - if self.sz > idx then
225 - return self.storage.ptr + (self.sz - (idx+1))
226 - else lib.bail('vector underrun!') end
227 - end;
228 - crush = terra(self: &v)
229 - self.storage:resize(self.sz)
230 - return self.storage
231 - end;
232 - }
233 - v.metamethods.__apply = terra(self: &v, idx: intptr): &ty -- no index??
234 - if self.sz > idx then
235 - return self.storage.ptr + idx
236 - else lib.bail('vector overrun!') end
237 - end
238 - return v
239 -end)
214 + return set
215 +end
240 216
241 217 lib.err = lib.loadlib('mbedtls','mbedtls/error.h')
242 218 lib.rsa = lib.loadlib('mbedtls','mbedtls/rsa.h')
243 219 lib.pk = lib.loadlib('mbedtls','mbedtls/pk.h')
244 220 lib.md = lib.loadlib('mbedtls','mbedtls/md.h')
245 221 lib.b64 = lib.loadlib('mbedtls','mbedtls/base64.h')
246 222 lib.net = lib.loadlib('mongoose','mongoose.h')
247 223 lib.pq = lib.loadlib('libpq','libpq-fe.h')
248 -lib.file = terralib.loadfile('file.t')()
249 -lib.math = terralib.loadfile('math.t')()
250 -lib.crypt = terralib.loadfile('crypt.t')()
251 -lib.http = terralib.loadfile('http.t')()
252 -lib.tpl = terralib.loadfile('tpl.t')()
253 -lib.string = terralib.loadfile('string.t')()
254 -lib.store = terralib.loadfile('store.t')()
224 +
225 +lib.load {
226 + 'mem', 'str', 'file', 'math', 'crypt';
227 + 'http', 'tpl', 'store';
228 +}
255 229
256 230 local be = {}
257 -for _, b in pairs { 'pgsql' } do
231 +for _, b in pairs(config.backends) do
258 232 be[#be+1] = terralib.loadfile('backend/' .. b .. '.t')()
259 233 end
260 234 lib.store.backends = global(`array([be]))
261 235
262 236 lib.cmdparse = terralib.loadfile('cmdparse.t')()
263 237 lib.srv = terralib.loadfile('srv.t')()
264 238
................................................................................
279 253
280 254 local pemdump = macro(function(pub, kp)
281 255 local msg = (pub:asvalue() and ' * emitting public key\n') or ' * emitting private key\n'
282 256 return quote
283 257 var buf: lib.crypt.pemfile
284 258 lib.mem.zero(buf)
285 259 lib.crypt.pem(pub, &kp, buf)
286 - lib.io.send(1, msg, [#msg])
287 - lib.io.send(1, [rawstring](&buf), lib.str.sz([rawstring](&buf)))
288 - lib.io.send(1, '\n', 1)
260 + lib.emit(msg, buf, '\n')
261 + --lib.io.send(1, msg, [#msg])
262 + --lib.io.send(1, [rawstring](&buf), lib.str.sz([rawstring](&buf)))
263 + --lib.io.send(1, '\n', 1)
289 264 end
290 265 end)
291 266
292 267 do
293 268 local p = string.format('parsav: %s\nbuilt on %s\n', config.build.str, config.build.when)
294 269 terra version() lib.io.send(1, p, [#p]) end
295 270 end
................................................................................
303 278 end
304 279 noise = 1
305 280 end
306 281
307 282 local options = lib.cmdparse {
308 283 version = {'V', 'display information about the binary build and exit'};
309 284 quiet = {'q', 'do not print to standard out'};
310 - help = {'h', 'display this list'}
285 + help = {'h', 'display this list'};
286 + backend_file = {'b', 'init from specified backend file', 1};
311 287 }
312 288
313 289 terra entry(argc: int, argv: &rawstring): int
290 + if argc < 1 then lib.bail('bad invocation!') end
291 +
314 292 noise_init()
315 293 [lib.init]
316 294
317 295 -- shut mongoose the fuck up
318 296 lib.net.mg_log_set_callback([terra(msg: &opaque, sz: int, u: &opaque) end], nil)
297 + var srv: lib.srv
298 +
299 + do var mode: options
300 + mode:parse(argc,argv) defer mode:free()
301 + if mode.version then version() return 0 end
302 + if mode.help then
303 + lib.io.send(1, [options.helptxt], [#options.helptxt])
304 + return 0
305 + end
306 + var cnf: rawstring
307 + if mode.backend_file ~= 0
308 + then if mode.arglist.ct >= mode.backend_file
309 + then cnf = mode.arglist.ptr[mode.backend_file - 1]
310 + else lib.bail('bad invocation, backend file not specified') end
311 + else cnf = lib.proc.getenv('parsav_backend_file')
312 + end
313 + if cnf == nil then cnf = "backend.conf" end
319 314
320 - var mode: options
321 - mode:parse(argc,argv)
322 - if mode.version then
323 - version()
324 - return 0
315 + srv:start(cnf)
325 316 end
326 - if mode.help then
327 - lib.io.send(1, [options.helptxt], [#options.helptxt])
328 - return 0
329 - end
330 - var srv: lib.srv
331 - srv:start('backend.conf')
317 +
332 318 lib.report('listening for requests')
333 319 while true do
334 320 srv:poll()
335 321 end
336 322 srv:shutdown()
337 323
338 324 return 0
................................................................................
345 331 end
346 332
347 333 if bflag('dump-config','C') then
348 334 print(util.dump(config))
349 335 os.exit(0)
350 336 end
351 337
352 -local emit = print
353 -if bflag('quiet','q') then emit = function() end end
354 -
338 +local holler = print
355 339 local out = config.exe and 'parsav' or 'parsav.o'
356 340 local linkargs = {}
341 +
342 +if bflag('quiet','q') then holler = function() end end
343 +if bflag('asan','s') then linkargs[#linkargs+1] = '-fsanitize=address' end
344 +if bflag('lsan','S') then linkargs[#linkargs+1] = '-fsanitize=leak' end
345 +
357 346 if config.posix then
358 347 linkargs[#linkargs+1] = '-pthread'
359 348 end
360 349 for _,p in pairs(config.pkg) do util.append(linkargs, p.linkargs) end
361 -emit('linking with args',util.dump(linkargs))
350 +holler('linking with args',util.dump(linkargs))
362 351 terralib.saveobj(out, {
363 352 main = entry
364 353 },
365 354 linkargs,
366 355 config.tgttrip and terralib.newtarget {
367 356 Triple = config.tgttrip;
368 357 CPU = config.tgtcpu;
369 358 FloatABIHard = config.tgthf;
370 359 } or nil)