########################################################################## # # Copyright 2008-2010 VMware, Inc. # All Rights Reserved. # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # ##########################################################################/ """C basic types""" import sys import debug class Type: """Base class for all types.""" __tags = set() def __init__(self, expr, tag = None): self.expr = expr # Generate a default tag, used when naming functions that will operate # on this type, so it should preferrably be something representative of # the type. if tag is None: if expr is not None: tag = ''.join([c for c in expr if c.isalnum() or c in '_']) else: tag = 'anonynoums' else: for c in tag: assert c.isalnum() or c in '_' # Ensure it is unique. if tag in Type.__tags: suffix = 1 while tag + str(suffix) in Type.__tags: suffix += 1 tag += str(suffix) assert tag not in Type.__tags Type.__tags.add(tag) self.tag = tag def __str__(self): """Return the C/C++ type expression for this type.""" return self.expr def visit(self, visitor, *args, **kwargs): raise NotImplementedError def mutable(self): '''Return a mutable version of this type. Convenience wrapper around MutableRebuilder.''' visitor = MutableRebuilder() return visitor.visit(self) def depends(self, other): '''Whether this type depends on another.''' collector = Collector() collector.visit(self) return other in collector.types class _Void(Type): """Singleton void type.""" def __init__(self): Type.__init__(self, "void") def visit(self, visitor, *args, **kwargs): return visitor.visitVoid(self, *args, **kwargs) Void = _Void() class Literal(Type): """Class to describe literal types. Types which are not defined in terms of other types, such as integers and floats.""" def __init__(self, expr, kind): Type.__init__(self, expr) self.kind = kind def visit(self, visitor, *args, **kwargs): return visitor.visitLiteral(self, *args, **kwargs) Bool = Literal("bool", "Bool") SChar = Literal("signed char", "SInt") UChar = Literal("unsigned char", "UInt") Short = Literal("short", "SInt") Int = Literal("int", "SInt") Long = Literal("long", "SInt") LongLong = Literal("long long", "SInt") UShort = Literal("unsigned short", "UInt") UInt = Literal("unsigned int", "UInt") ULong = Literal("unsigned long", "UInt") ULongLong = Literal("unsigned long long", "UInt") Float = Literal("float", "Float") Double = Literal("double", "Double") SizeT = Literal("size_t", "UInt") Char = Literal("char", "SInt") WChar = Literal("wchar_t", "SInt") Int8 = Literal("int8_t", "SInt") UInt8 = Literal("uint8_t", "UInt") Int16 = Literal("int16_t", "SInt") UInt16 = Literal("uint16_t", "UInt") Int32 = Literal("int32_t", "SInt") UInt32 = Literal("uint32_t", "UInt") Int64 = Literal("int64_t", "SInt") UInt64 = Literal("uint64_t", "UInt") IntPtr = Literal("intptr_t", "SInt") UIntPtr = Literal("uintptr_t", "UInt") class Const(Type): def __init__(self, type): # While "const foo" and "foo const" are synonymous, "const foo *" and # "foo * const" are not quite the same, and some compilers do enforce # strict const correctness. if type.expr.startswith("const ") or '*' in type.expr: expr = type.expr + " const" else: # The most legible expr = "const " + type.expr Type.__init__(self, expr, 'C' + type.tag) self.type = type def visit(self, visitor, *args, **kwargs): return visitor.visitConst(self, *args, **kwargs) class Pointer(Type): def __init__(self, type): Type.__init__(self, type.expr + " *", 'P' + type.tag) self.type = type def visit(self, visitor, *args, **kwargs): return visitor.visitPointer(self, *args, **kwargs) class IntPointer(Type): '''Integer encoded as a pointer.''' def visit(self, visitor, *args, **kwargs): return visitor.visitIntPointer(self, *args, **kwargs) class ObjPointer(Type): '''Pointer to an object.''' def __init__(self, type): Type.__init__(self, type.expr + " *", 'P' + type.tag) self.type = type def visit(self, visitor, *args, **kwargs): return visitor.visitObjPointer(self, *args, **kwargs) class LinearPointer(Type): '''Pointer to a linear range of memory.''' def __init__(self, type, size = None): Type.__init__(self, type.expr + " *", 'P' + type.tag) self.type = type self.size = size def visit(self, visitor, *args, **kwargs): return visitor.visitLinearPointer(self, *args, **kwargs) class Reference(Type): '''C++ references.''' def __init__(self, type): Type.__init__(self, type.expr + " &", 'R' + type.tag) self.type = type def visit(self, visitor, *args, **kwargs): return visitor.visitReference(self, *args, **kwargs) class Handle(Type): def __init__(self, name, type, range=None, key=None): Type.__init__(self, type.expr, 'P' + type.tag) self.name = name self.type = type self.range = range self.key = key def visit(self, visitor, *args, **kwargs): return visitor.visitHandle(self, *args, **kwargs) def ConstPointer(type): return Pointer(Const(type)) class Enum(Type): __id = 0 def __init__(self, name, values): Type.__init__(self, name) self.id = Enum.__id Enum.__id += 1 self.values = list(values) def visit(self, visitor, *args, **kwargs): return visitor.visitEnum(self, *args, **kwargs) def FakeEnum(type, values): return Enum(type.expr, values) class Bitmask(Type): __id = 0 def __init__(self, type, values): Type.__init__(self, type.expr) self.id = Bitmask.__id Bitmask.__id += 1 self.type = type self.values = values def visit(self, visitor, *args, **kwargs): return visitor.visitBitmask(self, *args, **kwargs) Flags = Bitmask class Array(Type): def __init__(self, type_, length): Type.__init__(self, type_.expr + " *") self.type = type_ self.length = length if not isinstance(length, int): assert isinstance(length, basestring) # Check if length is actually a valid constant expression try: eval(length, {}, {}) except: pass else: raise ValueError("length %r should be an integer" % length) def visit(self, visitor, *args, **kwargs): return visitor.visitArray(self, *args, **kwargs) class AttribArray(Type): def __init__(self, baseType, valueTypes, terminator = '0'): self.baseType = baseType Type.__init__(self, (Pointer(self.baseType)).expr) self.valueTypes = valueTypes self.terminator = terminator self.hasKeysWithoutValues = False for key, value in valueTypes: if value is None: self.hasKeysWithoutValues = True def visit(self, visitor, *args, **kwargs): return visitor.visitAttribArray(self, *args, **kwargs) class Blob(Type): def __init__(self, type, size): Type.__init__(self, type.expr + ' *') self.type = type self.size = size def visit(self, visitor, *args, **kwargs): return visitor.visitBlob(self, *args, **kwargs) class Struct(Type): __id = 0 def __init__(self, name, members): Type.__init__(self, name) self.id = Struct.__id Struct.__id += 1 self.name = name self.members = members def visit(self, visitor, *args, **kwargs): return visitor.visitStruct(self, *args, **kwargs) def Union(kindExpr, kindTypes, contextLess=True): switchTypes = [] for kindCase, kindType, kindMemberName in kindTypes: switchType = Struct(None, [(kindType, kindMemberName)]) switchTypes.append((kindCase, switchType)) return Polymorphic(kindExpr, switchTypes, contextLess=contextLess) class Alias(Type): def __init__(self, expr, type): Type.__init__(self, expr) self.type = type def visit(self, visitor, *args, **kwargs): return visitor.visitAlias(self, *args, **kwargs) class Arg: def __init__(self, type, name, input=True, output=False): self.type = type self.name = name self.input = input self.output = output self.index = None def __str__(self): return '%s %s' % (self.type, self.name) def In(type, name): return Arg(type, name, input=True, output=False) def Out(type, name): return Arg(type, name, input=False, output=True) def InOut(type, name): return Arg(type, name, input=True, output=True) class Function: def __init__(self, type, name, args, call = '', fail = None, sideeffects=True, internal=False, overloaded=False): self.type = type self.name = name self.args = [] index = 0 for arg in args: if not isinstance(arg, Arg): if isinstance(arg, tuple): arg_type, arg_name = arg else: arg_type = arg arg_name = "arg%u" % index arg = Arg(arg_type, arg_name) arg.index = index index += 1 self.args.append(arg) self.call = call self.fail = fail self.sideeffects = sideeffects self.internal = internal self.overloaded = overloaded def prototype(self, name=None): if name is not None: name = name.strip() else: name = self.name s = name if self.call: s = self.call + ' ' + s if name.startswith('*'): s = '(' + s + ')' s = self.type.expr + ' ' + s s += "(" if self.args: s += ", ".join(["%s %s" % (arg.type, arg.name) for arg in self.args]) else: s += "void" s += ")" return s def sigName(self): name = self.name if self.overloaded: # suffix used to make overloaded functions/methods unique suffix = ','.join([str(arg.type) for arg in self.args]) suffix = suffix.replace(' *', '*') suffix = suffix.replace(' &', '&') suffix = '(' + suffix + ')' name += suffix return name def argNames(self): return [arg.name for arg in self.args] def getArgByName(self, name): for arg in self.args: if arg.name == name: return arg return None def getArgByType(self, type): for arg in self.args: if arg.type is type: return arg return None def StdFunction(*args, **kwargs): kwargs.setdefault('call', '__stdcall') return Function(*args, **kwargs) def FunctionPointer(type, name, args, **kwargs): # XXX: We should probably treat function pointers (callbacks or not) in a generic fashion return Opaque(name) class Interface(Type): def __init__(self, name, base=None): Type.__init__(self, name) self.name = name self.base = base self.methods = [] def visit(self, visitor, *args, **kwargs): return visitor.visitInterface(self, *args, **kwargs) def getMethodByName(self, name): for method in self.iterMethods(): if method.name == name: return method return None def iterMethods(self): if self.base is not None: for method in self.base.iterMethods(): yield method for method in self.methods: yield method raise StopIteration def iterBases(self): iface = self while iface is not None: yield iface iface = iface.base raise StopIteration def hasBase(self, *bases): for iface in self.iterBases(): if iface in bases: return True return False def iterBaseMethods(self): if self.base is not None: for iface, method in self.base.iterBaseMethods(): yield iface, method for method in self.methods: yield self, method raise StopIteration class Method(Function): def __init__(self, type, name, args, call = '', const=False, sideeffects=True, overloaded=False): assert call == '__stdcall' Function.__init__(self, type, name, args, call = call, sideeffects=sideeffects, overloaded=overloaded) for index in range(len(self.args)): self.args[index].index = index + 1 self.const = const def prototype(self, name=None): s = Function.prototype(self, name) if self.const: s += ' const' return s def StdMethod(*args, **kwargs): kwargs.setdefault('call', '__stdcall') return Method(*args, **kwargs) class String(Type): '''Human-legible character string.''' def __init__(self, type = Char, length = None, wide = False): assert isinstance(type, Type) Type.__init__(self, type.expr + ' *') self.type = type self.length = length self.wide = wide def visit(self, visitor, *args, **kwargs): return visitor.visitString(self, *args, **kwargs) class Opaque(Type): '''Opaque pointer.''' def __init__(self, expr): Type.__init__(self, expr) def visit(self, visitor, *args, **kwargs): return visitor.visitOpaque(self, *args, **kwargs) def OpaquePointer(type, *args): return Opaque(type.expr + ' *') def OpaqueArray(type, size): return Opaque(type.expr + ' *') def OpaqueBlob(type, size): return Opaque(type.expr + ' *') class Polymorphic(Type): def __init__(self, switchExpr, switchTypes, defaultType=None, contextLess=True): if defaultType is None: Type.__init__(self, None) contextLess = False else: Type.__init__(self, defaultType.expr) self.switchExpr = switchExpr self.switchTypes = switchTypes self.defaultType = defaultType self.contextLess = contextLess def visit(self, visitor, *args, **kwargs): return visitor.visitPolymorphic(self, *args, **kwargs) def iterSwitch(self): cases = [] types = [] if self.defaultType is not None: cases.append(['default']) types.append(self.defaultType) for expr, type in self.switchTypes: case = 'case %s' % expr try: i = types.index(type) except ValueError: cases.append([case]) types.append(type) else: cases[i].append(case) return zip(cases, types) def EnumPolymorphic(enumName, switchExpr, switchTypes, defaultType, contextLess=True): enumValues = [expr for expr, type in switchTypes] enum = Enum(enumName, enumValues) polymorphic = Polymorphic(switchExpr, switchTypes, defaultType, contextLess) return enum, polymorphic class Visitor: '''Abstract visitor for the type hierarchy.''' def visit(self, type, *args, **kwargs): return type.visit(self, *args, **kwargs) def visitVoid(self, void, *args, **kwargs): raise NotImplementedError def visitLiteral(self, literal, *args, **kwargs): raise NotImplementedError def visitString(self, string, *args, **kwargs): raise NotImplementedError def visitConst(self, const, *args, **kwargs): raise NotImplementedError def visitStruct(self, struct, *args, **kwargs): raise NotImplementedError def visitArray(self, array, *args, **kwargs): raise NotImplementedError def visitAttribArray(self, array, *args, **kwargs): raise NotImplementedError def visitBlob(self, blob, *args, **kwargs): raise NotImplementedError def visitEnum(self, enum, *args, **kwargs): raise NotImplementedError def visitBitmask(self, bitmask, *args, **kwargs): raise NotImplementedError def visitPointer(self, pointer, *args, **kwargs): raise NotImplementedError def visitIntPointer(self, pointer, *args, **kwargs): raise NotImplementedError def visitObjPointer(self, pointer, *args, **kwargs): raise NotImplementedError def visitLinearPointer(self, pointer, *args, **kwargs): raise NotImplementedError def visitReference(self, reference, *args, **kwargs): raise NotImplementedError def visitHandle(self, handle, *args, **kwargs): raise NotImplementedError def visitAlias(self, alias, *args, **kwargs): raise NotImplementedError def visitOpaque(self, opaque, *args, **kwargs): raise NotImplementedError def visitInterface(self, interface, *args, **kwargs): raise NotImplementedError def visitPolymorphic(self, polymorphic, *args, **kwargs): raise NotImplementedError #return self.visit(polymorphic.defaultType, *args, **kwargs) class OnceVisitor(Visitor): '''Visitor that guarantees that each type is visited only once.''' def __init__(self): self.__visited = set() def visit(self, type, *args, **kwargs): if type not in self.__visited: self.__visited.add(type) return type.visit(self, *args, **kwargs) return None class Rebuilder(Visitor): '''Visitor which rebuild types as it visits them. By itself it is a no-op -- it is intended to be overwritten. ''' def visitVoid(self, void): return void def visitLiteral(self, literal): return literal def visitString(self, string): string_type = self.visit(string.type) if string_type is string.type: return string else: return String(string_type, string.length, string.wide) def visitConst(self, const): const_type = self.visit(const.type) if const_type is const.type: return const else: return Const(const_type) def visitStruct(self, struct): members = [(self.visit(type), name) for type, name in struct.members] return Struct(struct.name, members) def visitArray(self, array): type = self.visit(array.type) return Array(type, array.length) def visitBlob(self, blob): type = self.visit(blob.type) return Blob(type, blob.size) def visitEnum(self, enum): return enum def visitBitmask(self, bitmask): type = self.visit(bitmask.type) return Bitmask(type, bitmask.values) def visitPointer(self, pointer): pointer_type = self.visit(pointer.type) if pointer_type is pointer.type: return pointer else: return Pointer(pointer_type) def visitIntPointer(self, pointer): return pointer def visitObjPointer(self, pointer): pointer_type = self.visit(pointer.type) if pointer_type is pointer.type: return pointer else: return ObjPointer(pointer_type) def visitLinearPointer(self, pointer): pointer_type = self.visit(pointer.type) if pointer_type is pointer.type: return pointer else: return LinearPointer(pointer_type) def visitReference(self, reference): reference_type = self.visit(reference.type) if reference_type is reference.type: return reference else: return Reference(reference_type) def visitHandle(self, handle): handle_type = self.visit(handle.type) if handle_type is handle.type: return handle else: return Handle(handle.name, handle_type, range=handle.range, key=handle.key) def visitAlias(self, alias): alias_type = self.visit(alias.type) if alias_type is alias.type: return alias else: return Alias(alias.expr, alias_type) def visitOpaque(self, opaque): return opaque def visitInterface(self, interface, *args, **kwargs): return interface def visitPolymorphic(self, polymorphic): switchExpr = polymorphic.switchExpr switchTypes = [(expr, self.visit(type)) for expr, type in polymorphic.switchTypes] if polymorphic.defaultType is None: defaultType = None else: defaultType = self.visit(polymorphic.defaultType) return Polymorphic(switchExpr, switchTypes, defaultType, polymorphic.contextLess) class MutableRebuilder(Rebuilder): '''Type visitor which derives a mutable type.''' def visitString(self, string): return string def visitConst(self, const): # Strip out const qualifier return const.type def visitAlias(self, alias): # Tear the alias on type changes type = self.visit(alias.type) if type is alias.type: return alias return type def visitReference(self, reference): # Strip out references return self.visit(reference.type) class Traverser(Visitor): '''Visitor which all types.''' def visitVoid(self, void, *args, **kwargs): pass def visitLiteral(self, literal, *args, **kwargs): pass def visitString(self, string, *args, **kwargs): pass def visitConst(self, const, *args, **kwargs): self.visit(const.type, *args, **kwargs) def visitStruct(self, struct, *args, **kwargs): for type, name in struct.members: self.visit(type, *args, **kwargs) def visitArray(self, array, *args, **kwargs): self.visit(array.type, *args, **kwargs) def visitAttribArray(self, attribs, *args, **kwargs): for key, valueType in attribs.valueTypes: if valueType is not None: self.visit(valueType, *args, **kwargs) def visitBlob(self, array, *args, **kwargs): pass def visitEnum(self, enum, *args, **kwargs): pass def visitBitmask(self, bitmask, *args, **kwargs): self.visit(bitmask.type, *args, **kwargs) def visitPointer(self, pointer, *args, **kwargs): self.visit(pointer.type, *args, **kwargs) def visitIntPointer(self, pointer, *args, **kwargs): pass def visitObjPointer(self, pointer, *args, **kwargs): self.visit(pointer.type, *args, **kwargs) def visitLinearPointer(self, pointer, *args, **kwargs): self.visit(pointer.type, *args, **kwargs) def visitReference(self, reference, *args, **kwargs): self.visit(reference.type, *args, **kwargs) def visitHandle(self, handle, *args, **kwargs): self.visit(handle.type, *args, **kwargs) def visitAlias(self, alias, *args, **kwargs): self.visit(alias.type, *args, **kwargs) def visitOpaque(self, opaque, *args, **kwargs): pass def visitInterface(self, interface, *args, **kwargs): if interface.base is not None: self.visit(interface.base, *args, **kwargs) for method in interface.iterMethods(): for arg in method.args: self.visit(arg.type, *args, **kwargs) self.visit(method.type, *args, **kwargs) def visitPolymorphic(self, polymorphic, *args, **kwargs): for expr, type in polymorphic.switchTypes: self.visit(type, *args, **kwargs) if polymorphic.defaultType is not None: self.visit(polymorphic.defaultType, *args, **kwargs) class Collector(Traverser): '''Visitor which collects all unique types as it traverses them.''' def __init__(self): self.__visited = set() self.types = [] def visit(self, type): if type in self.__visited: return self.__visited.add(type) Visitor.visit(self, type) self.types.append(type) class ExpanderMixin: '''Mixin class that provides a bunch of methods to expand C expressions from the specifications.''' __structs = None __indices = None def expand(self, expr): # Expand a C expression, replacing certain variables if not isinstance(expr, basestring): return expr variables = {} if self.__structs is not None: variables['self'] = '(%s)' % self.__structs[0] if self.__indices is not None: variables['i'] = self.__indices[0] expandedExpr = expr.format(**variables) if expandedExpr != expr and 0: sys.stderr.write(" %r -> %r\n" % (expr, expandedExpr)) return expandedExpr def visitMember(self, member, structInstance, *args, **kwargs): memberType, memberName = member if memberName is None: # Anonymous structure/union member memberInstance = structInstance else: memberInstance = '(%s).%s' % (structInstance, memberName) self.__structs = (structInstance, self.__structs) try: return self.visit(memberType, memberInstance, *args, **kwargs) finally: _, self.__structs = self.__structs def visitElement(self, elementIndex, elementType, *args, **kwargs): self.__indices = (elementIndex, self.__indices) try: return self.visit(elementType, *args, **kwargs) finally: _, self.__indices = self.__indices class Module: '''A collection of functions.''' def __init__(self, name = None): self.name = name self.headers = [] self.functions = [] self.interfaces = [] def addFunctions(self, functions): self.functions.extend(functions) def addInterfaces(self, interfaces): self.interfaces.extend(interfaces) def mergeModule(self, module): self.headers.extend(module.headers) self.functions.extend(module.functions) self.interfaces.extend(module.interfaces) def getFunctionByName(self, name): for function in self.functions: if function.name == name: return function return None class API: '''API abstraction. Essentially, a collection of types, functions, and interfaces. ''' def __init__(self, modules = None): self.modules = [] if modules is not None: self.modules.extend(modules) def getAllTypes(self): collector = Collector() for module in self.modules: for function in module.functions: for arg in function.args: collector.visit(arg.type) collector.visit(function.type) for interface in module.interfaces: collector.visit(interface) for method in interface.iterMethods(): for arg in method.args: collector.visit(arg.type) collector.visit(method.type) return collector.types def getAllFunctions(self): functions = [] for module in self.modules: functions.extend(module.functions) return functions def getAllInterfaces(self): types = self.getAllTypes() interfaces = [type for type in types if isinstance(type, Interface)] for module in self.modules: for interface in module.interfaces: if interface not in interfaces: interfaces.append(interface) return interfaces def addModule(self, module): self.modules.append(module) def getFunctionByName(self, name): for module in self.modules: for function in module.functions: if function.name == name: return function return None # C string (i.e., zero terminated) CString = String(Char) WString = String(WChar, wide=True) ConstCString = String(Const(Char)) ConstWString = String(Const(WChar), wide=True)