parsav  Diff

Differences From Artifact [ce122c09dc]:

To Artifact [fcc06cebed]:


     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)