cortav  Diff

Differences From Artifact [550cdedbd6]:

To Artifact [eb2c53bff4]:


     4      4   --  ? utility library with functionality common to
     5      5   --    cortav.lua and its extensions
     6      6   --    from Ranuir "software utility"
     7      7   --  > local ss = require 'sirsem.lua'
     8      8   
     9      9   local ss
    10     10   do -- pull ourselves up by our own bootstraps
    11         -	local package = _G.package -- prevent namespace from being broken by env shenanigans
           11  +	local package = _G.package
           12  +	-- prevent namespace from being broken by env shenanigans
    12     13   	local function namespace(name, tbl)
    13     14   		local pkg = tbl or {}
    14     15   		if package then
    15     16   			package.loaded[name] = pkg
    16     17   		end
    17     18   		return pkg
    18     19   	end
................................................................................
   600    601   
   601    602   	if c.op then
   602    603   		cls.__add = c.op.sum
   603    604   		cls.__sub = c.op.sub
   604    605   		cls.__div = c.op.div
   605    606   		cls.__mul = c.op.mul
   606    607   		cls.__concat = c.op.cat
          608  +		cls.__eq = c.op.eq
          609  +		cls.__lt = c.op.lt
   607    610   	end
   608    611   
   609    612   	cls.mk = function(...)
   610    613   		local val = setmetatable(c.mk and c.mk(...) or {}, cls)
   611    614   		if c.init then
   612    615   			for k,v in pairs(c.init) do
   613    616   				val[k] = v
................................................................................
   685    688   
   686    689   ss.version = ss.declare {
   687    690   	name = 'version';
   688    691   	mk = function(tbl) return tbl end;
   689    692   	fns = {
   690    693   		pre = function(self,other) end;
   691    694   		post = function(self,other) end;
   692         -		string = function(self) return tostring(self) end;		
          695  +		string = function(self) return tostring(self) end;
   693    696   	};
   694    697   	cast = {
   695    698   		string = function(vers)
   696    699   			if not(next(vers)) then return '0.0' end
   697    700   			local str = ''
   698    701   			for _,v in pairs(vers) do
   699    702   				if type(v) == 'string' then
................................................................................
   766    769   function ss.tuple.cdr(x, ...) return ... end
   767    770   
   768    771   ss.stack = ss.declare {
   769    772   	ident = 'stack';
   770    773   	mk = function() return {
   771    774   		top = 0;
   772    775   		store = {};
   773         -   } end;
          776  +	} end;
   774    777   	index = function(me, i)
   775    778   		if i <= 0 then
   776    779   			return me.store[me.top + i]
   777    780   		else
   778    781   			return me.store[i]
   779    782   		end
   780    783   	end;
   781    784   	fns = {
   782    785   		push = function(me, val, ...)
   783         -         if val~=nil then
   784         -	         me.top = me.top + 1
   785         -	         me.store[me.top] = val
   786         -	         me:push(...)
   787         -         end
   788         -         return val, ...
   789         -      end;
   790         -      pop = function(me,n) n = n or 1
   791         -         local r = {}
          786  +			if val~=nil then
          787  +				me.top = me.top + 1
          788  +				me.store[me.top] = val
          789  +				me:push(...)
          790  +			end
          791  +			return val, ...
          792  +		end;
          793  +		pop = function(me,n) n = n or 1
          794  +			local r = {}
   792    795   			if n < me.top then
   793    796   				for i = 0,n-1 do
   794    797   					r[i+1] = me.store[me.top - i]
   795    798   					me.store[me.top - i] = nil
   796    799   				end
   797    800   				me.top = me.top - n
   798         -         else
   799         -	         r = me.store
          801  +			else
          802  +				r = me.store
   800    803   				me.store = {}
   801         -         end
          804  +			end
   802    805   			return table.unpack(r)
   803         -      end;
   804         -      set = function(me,val)
   805         -         if me.top == 0 then
   806         -	         me.top = me.top + 1 --autopush
   807         -         end
   808         -         me.store[me.top] = val
   809         -      end;
   810         -      all = function(me) return table.unpack(me.store) end;
   811         -      each = function(forward)
   812         -         if forward then
   813         -	         local idx = 0
   814         -	         return function()
   815         -		         idx = idx + 1
   816         -		         if idx > top
          806  +		end;
          807  +		set = function(me,val)
          808  +			if me.top == 0 then
          809  +				me.top = me.top + 1 --autopush
          810  +			end
          811  +			me.store[me.top] = val
          812  +		end;
          813  +		all = function(me) return table.unpack(me.store) end;
          814  +		each = function(me,forward)
          815  +			if forward then
          816  +				local idx = 0
          817  +				return function()
          818  +					idx = idx + 1
          819  +					if idx > me.top
          820  +						then return nil
          821  +						else return me.store[idx], idx
          822  +					end
          823  +				end
          824  +			else
          825  +				local idx = me.top + 1
          826  +				return function()
          827  +					idx = idx - 1
          828  +					if idx == 0
   817    829   						then return nil
   818    830   						else return me.store[idx], idx
   819    831   					end
   820         -	         end
   821         -         else
   822         -	         local idx = top + 1
   823         -	         return function()
   824         -		         idx = idx - 1
   825         -		         if idx == 0
   826         -						then return nil
   827         -						else return me.store[idx], idx
   828         -					end
   829         -	         end
   830         -         end
   831         -      end;
          832  +				end
          833  +			end
          834  +		end;
   832    835   	};
   833    836   }
   834    837   
   835    838   ss.automat = ss.declare {
   836    839   	ident = 'automat';
   837    840   	mk = function() return {
   838    841   		state = ss.stack();
................................................................................
  1107   1110   			-- versions at least can launch programs in a sane and secure
  1108   1111   			-- way.
  1109   1112   		else
  1110   1113   			return s
  1111   1114   		end
  1112   1115   	end, ...))
  1113   1116   end
         1117  +
         1118  +ss.mime = ss.declare {
         1119  +	ident = 'mime-type';
         1120  +	mk = function() return {
         1121  +		class = nil;
         1122  +		kind = nil;
         1123  +		opts = {};
         1124  +	} end;
         1125  +	construct = function(me,str)
         1126  +		if not str then return end
         1127  +		local p,o = str:match '^([^;]+);?%s*(.-)$'
         1128  +		if not p then ss.mime.exn('invalid type syntax %s',str):throw() end
         1129  +		local c,k = p:match '^([^/]+)/?(.-)$'
         1130  +		me.class = (c ~= '') and c or nil
         1131  +		me.kind = (k ~= '') and k or nil
         1132  +		if o and o ~= '' then
         1133  +			for key, e, val in o:gmatch '%s*([^=;]+)(=?)([^;]*)' do
         1134  +				if me.opts[key] then
         1135  +					ss.mime.exn('mime type cannot contain multiple %s options',key):throw()
         1136  +				elseif me.opts.hex    and key == 'base64'
         1137  +				    or me.opts.base64 and key == 'hex' then
         1138  +					ss.mime.exn('mime type cannot more than one of (base64, hex)',key):throw()
         1139  +				end
         1140  +				if e == '' then val = true end
         1141  +				me.opts[key] = val
         1142  +			end
         1143  +		end
         1144  +	end;
         1145  +	op = {
         1146  +		eq = function(self, other)
         1147  +		-- exact match operator
         1148  +			if not ss.mime.is(other) then return ss.mime.exn("tried to compare MIME type %s against %s (%s)", tostring(self), type(other), tostring(other)):throw() end
         1149  +			if (self.kind  == other.kind  or (self.kind == '*' or other.kind == '*')) and
         1150  +			   (self.class == other.class or (self.class == '*' or other.class == '*')) and
         1151  +			  (#self.opts  ==#other.opts) then
         1152  +				for k,v in pairs(self.opts) do
         1153  +					if not(other.opts[k] == '*' or (v == '*' and other.opts[k])) then
         1154  +						if other.opts[k] ~= v then return false end
         1155  +					end
         1156  +				end
         1157  +				for k,v in pairs(other.opts) do
         1158  +					if not(self.opts[k] == '*' or (v == '*' and self.opts[k])) then
         1159  +						if self.opts[k] ~= v then return false end
         1160  +					end
         1161  +				end
         1162  +				return true
         1163  +			else
         1164  +				return false
         1165  +			end
         1166  +		end;
         1167  +		lt = function(self,other)
         1168  +		-- lt is the "subset?" operator -- it returns true if self
         1169  +		-- matches at least as many fields as other has. use this
         1170  +		-- when you have a base type and want to check whether
         1171  +		-- another type is compatible with that type. say all you
         1172  +		-- care about is whether a file is "text/plain", and it
         1173  +		-- can be encoded however as long as that much fits.
         1174  +		-- you would then ask ss.mime'text/plain' < file.mime
         1175  +			return other:superset_of(self)
         1176  +		end;
         1177  +	};
         1178  +	cast = {
         1179  +		string = function(me)
         1180  +			local r
         1181  +			if me.kind and me.class then
         1182  +				r = string.format('%s/%s',me.class,me.kind)
         1183  +			elseif me.class then
         1184  +				r = me.class
         1185  +			end
         1186  +			for k,v in pairs(me.opts) do
         1187  +				if v and v ~= true then
         1188  +					r = r .. string.format(';%s=%s',k,v)
         1189  +				elseif v == true then
         1190  +					r = r .. string.format(';%s',k)
         1191  +				end
         1192  +			end
         1193  +			return r
         1194  +		end;
         1195  +	};
         1196  +	fns = {
         1197  +		superset_of = function(self, other)
         1198  +		-- a mime type is greater than another if all the fields
         1199  +		-- other has have a matching field in self. think of this
         1200  +		-- as the "superset?" operator -- all fields and options
         1201  +		-- on other must either match self or be unset
         1202  +			if not ss.mime.is(other) then return ss.mime.exn("tried to compare MIME type %s against %s (%s)", tostring(self), type(other), tostring(other)):throw() end
         1203  +			if (other.class and self.class ~= other.class and other.class ~='*')
         1204  +			or (other.kind  and self.kind  ~= other.kind  and other.kind ~= '*')
         1205  +				then return false end
         1206  +			for k,v in pairs(other.opts) do
         1207  +				if self.opts[k] and self.opts[k] ~= v and v ~='*' then
         1208  +					return false
         1209  +				end
         1210  +			end
         1211  +			return true
         1212  +		end;
         1213  +		is = function(me, pc)
         1214  +			local mimeclasses = {
         1215  +				['application/svg+xml'] = 'image';
         1216  +				['application/x-tar'] = 'archive';
         1217  +			}
         1218  +			local c = me.class
         1219  +			for k,v in pairs(mimeclasses) do
         1220  +				if me > ss.mime(k) then
         1221  +					c = v break
         1222  +				end
         1223  +			end
         1224  +			print(c)
         1225  +			return c == pc
         1226  +		end;
         1227  +	};
         1228  +}
         1229  +ss.mime.exn = ss.exnkind 'MIME error'