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