1import sys 2 3PASS_BY_VALUE = 1 4PASS_BY_REFERENCE = 2 5 6DIR_NONE = 0 7DIR_IN = 1 8DIR_OUT = 2 9DIR_BOTH = 3 10 11_default_namespace = "" 12def namespace(s): 13 if type(s) != str: 14 raise TypeError, "Require a string for the default namespace." 15 global _default_namespace 16 _default_namespace = s 17 18def _get_default_namespace(): 19 global _default_namespace 20 return _default_namespace 21 22_default_hidden = False 23def hidden(b): 24 global _default_hidden 25 _default_hidden = b 26 27def _get_default_hidden(): 28 global _default_hidden 29 return _default_hidden 30 31class Type(object): 32 def __init__(self, typename, **kwargs): 33 self.namespace = kwargs.setdefault('namespace', 34 _get_default_namespace()) 35 self._hidden = kwargs.setdefault('hidden', _get_default_hidden()) 36 self.dir = kwargs.setdefault('dir', DIR_BOTH) 37 if self.dir not in [DIR_NONE, DIR_IN, DIR_OUT, DIR_BOTH]: 38 raise ValueError 39 40 self.passby = kwargs.setdefault('passby', PASS_BY_VALUE) 41 if self.passby not in [PASS_BY_VALUE, PASS_BY_REFERENCE]: 42 raise ValueError 43 44 self.private = kwargs.setdefault('private', False) 45 46 if typename is None: # Anonymous type 47 self.typename = None 48 self.rawname = None 49 elif self.namespace is None: # e.g. system provided types 50 self.typename = typename 51 self.rawname = typename 52 else: 53 self.typename = self.namespace + typename 54 self.rawname = typename 55 56 if self.typename is not None: 57 self.dispose_fn = kwargs.setdefault('dispose_fn', self.typename + "_dispose") 58 else: 59 self.dispose_fn = kwargs.setdefault('dispose_fn', None) 60 61 self.autogenerate_dispose_fn = kwargs.setdefault('autogenerate_dispose_fn', True) 62 63 if self.typename is not None: 64 self.copy_fn = kwargs.setdefault('copy_fn', self.typename + "_copy") 65 else: 66 self.copy_fn = kwargs.setdefault('copy_fn', None) 67 68 self.autogenerate_copy_fn = kwargs.setdefault('autogenerate_copy_fn', True) 69 70 self.init_fn = kwargs.setdefault('init_fn', None) 71 self.init_val = kwargs.setdefault('init_val', None) 72 self.autogenerate_init_fn = kwargs.setdefault('autogenerate_init_fn', False) 73 74 self.check_default_fn = kwargs.setdefault('check_default_fn', None) 75 self.copy_deprecated_fn = kwargs.setdefault('copy_deprecated_fn', 76 None) 77 78 if self.typename is not None and not self.private: 79 self.json_gen_fn = kwargs.setdefault('json_gen_fn', self.typename + "_gen_json") 80 self.json_parse_type = kwargs.setdefault('json_parse_type', "JSON_ANY") 81 if self.namespace is not None: 82 self.json_parse_fn = kwargs.setdefault('json_parse_fn', 83 self.namespace + "_" + self.rawname + "_parse_json") 84 else: 85 self.json_parse_fn = kwargs.setdefault('json_parse_fn', 86 self.typename + "_parse_json") 87 else: 88 self.json_gen_fn = kwargs.setdefault('json_gen_fn', None) 89 self.json_parse_type = kwargs.setdefault('json_parse_type', None) 90 self.json_parse_fn = kwargs.setdefault('json_parse_fn', None) 91 92 self.autogenerate_json = kwargs.setdefault('autogenerate_json', True) 93 94 def marshal_in(self): 95 return self.dir in [DIR_IN, DIR_BOTH] 96 def marshal_out(self): 97 return self.dir in [DIR_OUT, DIR_BOTH] 98 99 def hidden(self): 100 if self._hidden: 101 return "_hidden " 102 else: 103 return "" 104 105 def make_arg(self, n, passby=None): 106 if passby is None: passby = self.passby 107 108 if passby == PASS_BY_REFERENCE: 109 return "%s *%s" % (self.typename, n) 110 else: 111 return "%s %s" % (self.typename, n) 112 113 def pass_arg(self, n, isref=None, passby=None): 114 if passby is None: passby = self.passby 115 if isref is None: isref = self.passby == PASS_BY_REFERENCE 116 117 if passby == PASS_BY_REFERENCE: 118 if isref: 119 return "%s" % (n) 120 else: 121 return "&%s" % (n) 122 else: 123 if isref: 124 return "*%s" % (n) 125 else: 126 return "%s" % (n) 127 128class Builtin(Type): 129 """Builtin type""" 130 def __init__(self, typename, **kwargs): 131 kwargs.setdefault('dispose_fn', None) 132 kwargs.setdefault('autogenerate_dispose_fn', False) 133 kwargs.setdefault('autogenerate_json', False) 134 Type.__init__(self, typename, **kwargs) 135 136class Number(Builtin): 137 def __init__(self, ctype, **kwargs): 138 kwargs.setdefault('namespace', None) 139 kwargs.setdefault('dispose_fn', None) 140 kwargs.setdefault('copy_fn', None) 141 kwargs.setdefault('signed', False) 142 kwargs.setdefault('json_gen_fn', "yajl_gen_integer") 143 kwargs.setdefault('json_parse_type', "JSON_INTEGER") 144 # json_parse_fn might be overriden on specific type 145 kwargs.setdefault('json_parse_fn', "libxl__int_parse_json") 146 self.signed = kwargs['signed'] 147 Builtin.__init__(self, ctype, **kwargs) 148 149class UInt(Number): 150 def __init__(self, w, **kwargs): 151 kwargs.setdefault('namespace', None) 152 kwargs.setdefault('dispose_fn', None) 153 kwargs.setdefault('json_parse_fn', "libxl__uint%d_parse_json" % w) 154 kwargs.setdefault('copy_fn', None) 155 Number.__init__(self, "uint%d_t" % w, **kwargs) 156 157 self.width = w 158 159class EnumerationValue(object): 160 def __init__(self, enum, value, name, **kwargs): 161 self.enum = enum 162 163 self.valuename = str.upper(name) 164 self.rawname = str.upper(enum.rawname) + "_" + self.valuename 165 self.name = str.upper(enum.value_namespace) + self.rawname 166 self.value = value 167 168class Enumeration(Type): 169 def __init__(self, typename, values, **kwargs): 170 kwargs.setdefault('dispose_fn', None) 171 kwargs.setdefault('copy_fn', None) 172 kwargs.setdefault('json_parse_type', "JSON_STRING") 173 Type.__init__(self, typename, **kwargs) 174 175 self.value_namespace = kwargs.setdefault('value_namespace', 176 self.namespace) 177 178 self.values = [] 179 for v in values: 180 # (value, name) 181 (num,name) = v 182 self.values.append(EnumerationValue(self, num, name, 183 typename=self.rawname)) 184 def lookup(self, name): 185 for v in self.values: 186 if v.valuename == str.upper(name): 187 return v 188 return ValueError 189 190class Field(object): 191 """An element of an Aggregate type""" 192 def __init__(self, type, name, **kwargs): 193 self.type = type 194 self.name = name 195 self.const = kwargs.setdefault('const', False) 196 self.enumname = kwargs.setdefault('enumname', None) 197 self.init_val = kwargs.setdefault('init_val', None) 198 self.deprecated_by = kwargs.setdefault('deprecated_by', None) 199 200class Aggregate(Type): 201 """A type containing a collection of other types""" 202 def __init__(self, kind, typename, fields, **kwargs): 203 kwargs.setdefault('json_parse_type', "JSON_MAP") 204 Type.__init__(self, typename, **kwargs) 205 206 if self.typename is not None: 207 self.init_fn = kwargs.setdefault('init_fn', self.typename + "_init") 208 else: 209 self.init_fn = kwargs.setdefault('init_fn', None) 210 211 self.autogenerate_init_fn = kwargs.setdefault('autogenerate_init_fn', True) 212 213 self.kind = kind 214 215 self.fields = [] 216 for f in fields: 217 # (name, type[, {kw args}]) 218 if len(f) == 2: 219 n,t = f 220 kw = {} 221 elif len(f) == 3: 222 n,t,kw = f 223 else: 224 raise ValueError 225 if n is None: 226 raise ValueError 227 self.fields.append(Field(t,n,**kw)) 228 229 # Returns a tuple (stem, field-expr) 230 # 231 # field-expr is a C expression for a field "f" within the struct 232 # "v". 233 # 234 # stem is the stem common to both "f" and any other sibbling field 235 # within the "v". 236 def member(self, v, f, isref): 237 if isref: 238 deref = v + "->" 239 else: 240 deref = v + "." 241 242 if f.name is None: # Anonymous 243 return (deref, deref) 244 else: 245 return (deref, deref + f.name) 246 247class Struct(Aggregate): 248 def __init__(self, name, fields, **kwargs): 249 kwargs.setdefault('passby', PASS_BY_REFERENCE) 250 Aggregate.__init__(self, "struct", name, fields, **kwargs) 251 252 def has_fields(self): 253 return len(self.fields) != 0 254 255class Union(Aggregate): 256 def __init__(self, name, fields, **kwargs): 257 # Generally speaking some intelligence is required to free a 258 # union therefore any specific instance of this class will 259 # need to provide an explicit destructor function. 260 kwargs.setdefault('passby', PASS_BY_REFERENCE) 261 kwargs.setdefault('dispose_fn', None) 262 Aggregate.__init__(self, "union", name, fields, **kwargs) 263 264class KeyedUnion(Aggregate): 265 """A union which is keyed of another variable in the parent structure""" 266 def __init__(self, name, keyvar_type, keyvar_name, fields, **kwargs): 267 Aggregate.__init__(self, "union", name, [], **kwargs) 268 269 if not isinstance(keyvar_type, Enumeration): 270 raise ValueError 271 272 kv_kwargs = dict([(x.lstrip('keyvar_'),y) for (x,y) in kwargs.items() if x.startswith('keyvar_')]) 273 274 self.keyvar = Field(keyvar_type, keyvar_name, **kv_kwargs) 275 276 for f in fields: 277 # (name, enum, type) 278 e, ty = f 279 ev = keyvar_type.lookup(e) 280 en = ev.name 281 self.fields.append(Field(ty, e, enumname=en)) 282 283# 284# Standard Types 285# 286 287void = Builtin("void *", namespace = None) 288bool = Builtin("bool", namespace = None, 289 copy_fn=None, 290 json_gen_fn = "yajl_gen_bool", 291 json_parse_type = "JSON_BOOL", 292 json_parse_fn = "libxl__bool_parse_json", 293 autogenerate_json = False) 294 295size_t = Number("size_t", namespace = None) 296 297integer = Number("int", namespace = None, signed = True) 298 299uint8 = UInt(8) 300uint16 = UInt(16) 301uint32 = UInt(32) 302uint64 = UInt(64, json_gen_fn = "libxl__uint64_gen_json") 303 304string = Builtin("char *", namespace = None, copy_fn = "libxl_string_copy", dispose_fn = "free", 305 json_gen_fn = "libxl__string_gen_json", 306 json_parse_type = "JSON_STRING | JSON_NULL", 307 json_parse_fn = "libxl__string_parse_json", 308 autogenerate_json = False, 309 check_default_fn="libxl__string_is_default") 310 311class Array(Type): 312 """An array of the same type""" 313 def __init__(self, elem_type, lenvar_name, **kwargs): 314 kwargs.setdefault('dispose_fn', 'free') 315 kwargs.setdefault('json_parse_type', 'JSON_ARRAY') 316 Type.__init__(self, namespace=elem_type.namespace, typename=elem_type.rawname + " *", **kwargs) 317 318 lv_kwargs = dict([(x.lstrip('lenvar_'),y) for (x,y) in kwargs.items() if x.startswith('lenvar_')]) 319 320 self.lenvar = Field(integer, lenvar_name, **lv_kwargs) 321 self.elem_type = elem_type 322 323class OrderedDict(dict): 324 """A dictionary which remembers insertion order. 325 326 push to back on duplicate insertion""" 327 328 def __init__(self): 329 dict.__init__(self) 330 self.__ordered = [] 331 332 def __setitem__(self, key, value): 333 try: 334 self.__ordered.remove(key) 335 except ValueError: 336 pass 337 338 self.__ordered.append(key) 339 dict.__setitem__(self, key, value) 340 341 def ordered_keys(self): 342 return self.__ordered 343 def ordered_values(self): 344 return [self[x] for x in self.__ordered] 345 def ordered_items(self): 346 return [(x,self[x]) for x in self.__ordered] 347 348def parse(f): 349 print >>sys.stderr, "Parsing %s" % f 350 351 globs = {} 352 locs = OrderedDict() 353 354 for n,t in globals().items(): 355 if isinstance(t, Type): 356 globs[n] = t 357 elif isinstance(t,type(object)) and issubclass(t, Type): 358 globs[n] = t 359 elif n in ['PASS_BY_REFERENCE', 'PASS_BY_VALUE', 360 'DIR_NONE', 'DIR_IN', 'DIR_OUT', 'DIR_BOTH', 361 'namespace', 'hidden']: 362 globs[n] = t 363 364 try: 365 execfile(f, globs, locs) 366 except SyntaxError,e: 367 raise SyntaxError, \ 368 "Errors were found at line %d while processing %s:\n\t%s"\ 369 %(e.lineno,f,e.text) 370 371 types = [t for t in locs.ordered_values() if isinstance(t,Type)] 372 373 builtins = [t for t in types if isinstance(t,Builtin)] 374 types = [t for t in types if not isinstance(t,Builtin)] 375 376 return (builtins,types) 377