Example #1
0
def findClassesAndLocations(where):
    """Return list of class names and dict of Class.cpp locations for each class"""
    classes = []
    locations = {}

    def appendClasses( fileName, classList, prefix ):
        for c in classList:
            c.name = prefix + c.name
            classes.append( c )
            locations[ c.name ] = fileName
            appendClasses( fileName, c._class, c.name )

    def findCppHeaders(top):
        for dirname, subdirs, files in os.walk(top):
            if not re.search('\\bUnitTest\\b', dirname):
                for f in  [ f for f in files if f.endswith(".h") ]:
                    yield os.path.join(dirname, f)

    for fileName in findCppHeaders(where):
        if util.hasReflectionDeclaration( open(fileName).read() ):
            dom = headerToDom.headerToDom( fileName )
            if dom.file.product != "NONE" and dom.file.platform != "NONE":
                filename = dom.file.destinationFilename(dom.localfilename, "Class.cpp")
                appendClasses( filename, dom.file._class, '' )                    
        
    return classes, locations
Example #2
0
 def get_reflected_files(where, lst):
     for f in lst:
         full = os.path.join(where,f)
         if f.endswith(".h"):
             content = open(full).read()
             tkbms = util.extract_tkbms(content)
             valid_tkbms = lambda x : (not tkbms.has_key(x) or tkbms[x] != "NONE")
             if valid_tkbms("platform") and valid_tkbms("product") and util.hasReflectionDeclaration(content):
                 yield full
         elif f.endswith(".hkclass") and not os.path.exists(full.replace(".hkclass",".h")):
             yield full
Example #3
0
 def get_reflected_files(where, lst):
     for f in lst:
         full = os.path.join(where,f)
         if f.endswith(".h"):
             content = open(full).read()
             tkbms = util.extract_tkbms(content)
             valid_tkbms = lambda x : (not tkbms.has_key(x) or tkbms[x] != "NONE")
             if valid_tkbms("platform") and valid_tkbms("product") and util.hasReflectionDeclaration(content):
                 yield full
         elif f.endswith(".hkclass") and not os.path.exists(full.replace(".hkclass",".h")):
             yield full
Example #4
0
def classToHeader(classfile, options):
    if options.verbose:
        print "Processing '%s'" % classfile
    dom = hkcToDom.hkcToDom(classfile)
    headerfile, cppfile = classfile.replace(".hkclass",".h"), classfile.replace(".hkclass","Class.cpp")
    try:
        if util.hasReflectionDeclaration(open(headerfile).read()):
            raise RuntimeError("'%s' contains HK_DECLARE_REFLECTION. Not overwriting" % headerfile)
    except IOError:
        pass
    writeIfDifferent( domToHeader.domToHeader(dom), headerfile )
    writeIfDifferent( domToClass.domToClass(dom), cppfile )
    if options.cvsignore:
        removeFromCvsignore(classfile)
        addToCvsignore(headerfile)
        addToCvsignore(cppfile)
Example #5
0
def processDir(where, options):
    ismeta = lambda f: f.endswith("h") and util.hasReflectionDeclaration(
        open(os.path.join(dirname, f)).read())
    nfile = 0
    for dirname, subdirs, files in os.walk(where):
        headers = [os.path.join(dirname, f) for f in files if ismeta(f)]
        hkclasses = [
            os.path.join(dirname, f) for f in files if f.endswith(".hkclass")
        ]
        generated = {}

        for header in headers:
            nfile += 1
            classfile = header.replace(".h", ".hkclass")
            if classfile in hkclasses:
                hkclasses.remove(classfile)
            headerToClass(header, options)
            generated[header.replace(".h", "Class.cpp")] = 1
        for hkcname in hkclasses:
            nfile += 1
            classToHeader(hkcname, options)
            generated[hkcname.replace(".hkclass", "Class.cpp")] = 1
        for f in [
                os.path.join(dirname, f) for f in files
                if (f.endswith("Class.cpp") and f != "hkClass.cpp")
        ]:
            if generated.get(f, 0) == 0 and not MAGIC_DESTINATION_MARK.search(
                    open(f).read()):  # rename stale files to numbered backup
                for i in range(0, 100):
                    try:
                        backup = "%s.%i" % (f, i)
                        open(backup)
                    except IOError:
                        print "STALE %s -> %s" % (f, backup)
                        os.rename(f, backup)
                        break
        try:
            subdirs.remove("CVS")
        except ValueError:
            pass
        if options.local_only:
            break

    if not options.quiet:
        print "DONE", where, nfile, "files processed"
Example #6
0
def classToHeader(classfile, options):
    if options.verbose:
        print "Processing '%s'" % classfile
    dom = hkcToDom.hkcToDom(classfile)
    headerfile, cppfile = classfile.replace(".hkclass",
                                            ".h"), classfile.replace(
                                                ".hkclass", "Class.cpp")
    try:
        if util.hasReflectionDeclaration(open(headerfile).read()):
            raise RuntimeError(
                "'%s' contains HK_DECLARE_REFLECTION. Not overwriting" %
                headerfile)
    except IOError:
        pass
    writeIfDifferent(domToHeader.domToHeader(dom), headerfile)
    writeIfDifferent(domToClass.domToClass(dom), cppfile)
    if options.cvsignore:
        removeFromCvsignore(classfile)
        addToCvsignore(headerfile)
        addToCvsignore(cppfile)
Example #7
0
def processDir(where, options):
    ismeta = lambda f : f.endswith("h") and util.hasReflectionDeclaration(open(os.path.join(dirname,f)).read())
    nfile = 0
    for dirname, subdirs, files in os.walk(where):
        headers = [ os.path.join(dirname,f) for f in files if ismeta(f) ]
        hkclasses = [ os.path.join(dirname,f) for f in files if f.endswith(".hkclass") ]
        generated = {}

        for header in headers:
            nfile += 1
            classfile = header.replace(".h",".hkclass")
            if classfile in hkclasses:
                hkclasses.remove(classfile)
            headerToClass(header, options)
            generated[header.replace(".h","Class.cpp")] = 1
        for hkcname in hkclasses:
            nfile += 1  
            classToHeader(hkcname, options)
            generated[hkcname.replace(".hkclass","Class.cpp")] = 1
        for f in [ os.path.join(dirname,f) for f in files if (f.endswith("Class.cpp") and f != "hkClass.cpp") ]:
            if generated.get(f,0) == 0 and not MAGIC_DESTINATION_MARK.search(open(f).read()): # rename stale files to numbered backup
                for i in range(0,100):
                    try:
                        backup = "%s.%i" % (f,i)
                        open( backup )
                    except IOError:
                        print "STALE %s -> %s" % (f,backup)
                        os.rename(f, backup)
                        break
        try:
            subdirs.remove("CVS")
        except ValueError:
            pass
        if options.local_only:
            break

    if not options.quiet:
        print "DONE", where, nfile, "files processed"
    def parseClass(self, match, txt, declaredscope):
        if match.group("decltype") == "{":
            self.debug("CLASS (%s) (%s) (%s) (%s)" % (match.group("type"), match.group("namespace"), match.group("name"), match.group("parents")))
            span = match.span()
            classEnd = self.findEndBrace(txt, span[1] )
            klass = hkcToDom.Class()
            klass.scope = declaredscope
            klass.fromheader = 1
            klass.name = match.group("name")
            parents = match.group("parents")
            if parents:
                getparentname = lambda x : x[len(x) > 1 and 1 or 0]
                parents = [getparentname(x.split()).split("<")[0].strip() for x in parents.split(",")]
                klass.parent = parents[0]
                for iname in parents[1:]:
                    ic = hkcToDom.Interface()
                    ic.name = iname
                    klass.interface.append( ic )
            body = txt[span[1]:classEnd-1]
            if match.group("type") == "class":
                currentAccess = "private"
            else:
                currentAccess = "public"
            
            def appendMember(mname, mtype, mvis, msrc, mflags=""):
                assert len(mname)
                if len(mtype) == 0:
	                print >>sys.stderr, "Error: MISSING STRING AFTER '%s'" % (mname)
                assert len(mtype)
                if mname.startswith("m_"):
                    mname = mname[2:]
                # check for synthetic member types
                if len(klass.member) >= 1:
                    prev = klass.member[-1]
                    prev2 = klass.member[-2] if len(klass.member) >= 2 else None
                    if mname.startswith("num") and mname[3:].lower() == prev.name.lower():
                        errPrefix = "%s::%s " % (klass.name, mname)
                        if prev2 and prev2.name.startswith(prev.name) and prev2.name.endswith("Class"):
                            assert prev.type == "void*"
                            assert prev2.type == "hkClass*"
                            prev2.name = prev.name
                            prev2.type = "hkHomogeneousArray"
                            assert prev2.visibility == mvis and prev.visibility == mvis, errPrefix + "homogeneous parts have differing visibility"
                            assert prev2.flags == "" and prev.flags == "", errPrefix + "homogeneous array attributes should go on last member"
                            prev2.flags = mflags
                            prev2.sourcecode += prev.sourcecode + msrc
                            klass.member.pop()
                            return
                        elif prev.type.endswith("*"):
                            prev.type = "hkSimpleArray<%s>" % prev.type.rsplit("*",1)[0].rstrip()
                            assert prev.visibility == mvis, errPrefix + "simplearray parts have differing visibility"
                            assert prev.flags == "", errPrefix + "simplearray attributes should apply to last member"
                            prev.flags = mflags
                            prev.sourcecode += msrc
                            return
                    elif mname.endswith("Class") and prev.name==mname[:-5] \
                            and mtype=="hkClass*" and prev.type=="void*":
                        prev.type = "hkVariant"
                        return
                member = hkcToDom.Member()
                member.name = mname
                member.type = mtype
                member.visibility = mvis
                member.flags = mflags
                member.sourcecode = msrc
                klass.member.append(member)

            def appendMethod(mtxt, parameters, qualifiers, visibility):
                if 0 not in [ mtxt.find(ignore) == -1 for ignore in "HK_DECLARE HK_ALIGN HK_SPU_VIRTUAL_DECLSPEC".split() ]:
                    def extract(txt, reg):
                        out = re.sub(reg, "", txt)
                        return out, txt!=out
                    method = hkcToDom.Method()
                    method.description = "%s(%s)%s" % (mtxt,parameters,qualifiers)
                    method.visibility = visibility
                    mtxt, method.inline = extract(mtxt, r"\b(inline|HK_FORCE_INLINE)\b")
                    mtxt, method.virtual = extract(mtxt, r"\bvirtual\b")
                    mtxt, method.static = extract(mtxt, r"\bstatic\b")
                    mtxt, constness = extract(mtxt, r"\b(const|explicit)\b")
                    qualifiers, method.const = extract(qualifiers, r"\bconst\b")
                    qualifiers, method.purevirtual = extract(qualifiers, "=\s*0")
                    qualifiers, initializers = extract(qualifiers, r"([:,]\s*\w+\s*\([^\)]*\))+")
                    if qualifiers.replace(")","").strip() != "":
                        print >>sys.stderr, "---------------UNPARSED '%s' in '%s'" % (qualifiers,mtxt)
                    method.name = mtxt.split()[-1]
                    if killwhitespace(parameters):
                        for i, x in enumerate(parameters.split(",")):
                            param = hkcToDom.Parameter()
                            param.description = x
                            valuelist = x.split("=")
                            if len(valuelist) == 2:
                                param.default = valuelist[-1].lstrip()
                            plist = valuelist[0].split()
                            if len([v for v in plist if v != "const"]) > 1 \
                                and plist[-1] not in [">", "*", "&"]:
                                param.name = plist[-1]
                                param.type = " ".join(v for v in plist[:-1] if v != "const")
                            else:
                                param.type = " ".join(v for v in plist if v != "const")
                                param.name = "noname_"+str(i)
                            method.parameter.append(param)
                    if klass.name == method.name:
                        self.debug("CONSTRUCTOR(%s,%s)" % (method.name, parameters))
                        assert len(mtxt.split()) == 1
                        klass.method.append( method )
                    elif "~"+klass.name == method.name:
                        self.debug("DESTRUCTOR(%s)" % (method.name))
                        assert len(mtxt.split()) == 1
                        assert len(method.parameter) == 0
                    else:
                        method.returns = " ".join( mtxt.split()[:-1] )
                        self.debug("METHOD(%s,%s::%s,%s)" % (method.returns, klass.name, method.name, parameters))
                        klass.method.append( method )
            lastParsed = None
            while 1:
                item, match = self.classMatcher.run(body)
                if match == None:
                    break

                newbody = None
                if item == self.re_accessControl:
                    currentAccess = match.group(1)
                    item = lastParsed # don't affect lastParsed
                elif item == self.re_classStart:
                    newbody, k = self.parseClass(match, body, klass)
                    if k:
                        klass._class.append(k)
                elif item == self.re_enumStart:
                    newbody, enum = self.parseEnum(match, body)
                    if enum:
                        enum.scope = klass
                        klass.enum.append(enum)
                elif item == self.re_unionStart:
                    newbody, union = self.parseUnion(match, body)
                elif item == self.re_attributesPlaceholder:
                    newbody, attrs = self.parseAttributes(match, body)
                    if lastParsed == None:
                        target = klass
                    elif lastParsed == self.re_classMember:
                        if klass.member:
                            target = klass.member[-1]
                        else:
                            target = None
                    elif lastParsed == self.re_typedef:
                        target = None # ignore attrs on typedefs for now
                    else:
                        raise "Unhandled case for attributes"
                    if target:
                        nosaveflag = False # apply nosave at end
                        for k,v in attrs:
                            if k=="nosave":
                                target.serialized = False
                                nosaveflag = True
                            else:
                                applyAttr(target, k, v)
                        if nosaveflag:
                            t = target.overridetype or target.type
                            if t.endswith("*"):
                                target.overridetype = "void*"
                            else:
                                partial = re.match("(hkArray|hkSimpleArray|hkEnum|hkFlags)\s*<\s*([^>,]+)\s*(,[^>]+)?\s*>", t)
                                if partial:
                                    stem, c, sz = partial.groups()
                                    target.overridetype = stem + ("<void*" if c.strip().endswith("*") else "<void") + (sz or "") + ">"
                    item = lastParsed # don't affect lastParsed
                elif item == self.re_classMethod:
                    span = match.span()
                    # actually a function pointer
                    if self.re_functionPointer.search(match.group()):
                        mtype = "void*"
                        mname = match.group().split("(")[1].split("*")[1].split(")")[0].split()[-1]
                        self.debug("MEMBER (%s)" % match.group())
                        appendMember(mname, mtype, currentAccess, match.group() )
                    if util.hasReflectionDeclaration(match.group()):
                        self.debug(match.group())
                        klass.reflected = True
                    elif self.re_memDeclaration.search(match.group()):
                        klass.memory_declaration = (currentAccess, match.group())
                        self.debug("%s (%s)" % (match.group(), currentAccess))
                    else:
                        if not klass.abstract and killwhitespace(match.group("qualifiers")).find("=0") != -1:
                            self.debug("ABSTRACT")
                            klass.abstract = True
                        elif not klass.vtable and "virtual" in match.group().split():
                            self.debug("VIRTUAL")
                            klass.vtable = True
                        appendMethod(match.group("method"), match.group("params"), match.group("qualifiers"), currentAccess )
                    if match.group("decltype") == "{":
                        methodEnd = self.findEndBrace(body, span[1] )
                        newbody = body[methodEnd:]
                elif item == self.re_classMember:
                    bits = self.re_constInDecl.sub(" ", match.group().rstrip(";"))
                    bits = self.re_whitespaceInArray.sub(r"[\1]", bits).split()
                    if bits[0] not in ("friend", "static", "typedef"):
                        mtype, mname = " ".join(bits[:-1]), bits[-1]
                        k = klass #todo: should lookup parent first, but often don't have definition
                        while k: # look at enclosing scopes too
                            mtype = k.typedef.get(mtype, mtype)
                            k = k.scope
                        mflags = ""
                        if bits[0] == "enum":
                            print "%s:Implicitly sized enum is not portable (%s). Use hkEnum<> instead." % (self.location_of(re.compile("^\s*enum[^;]*"+bits[2],re.M)), " ".join(bits))
                        arrayBegin = mname.find("[")
                        if arrayBegin != -1:
                            mtype += mname[arrayBegin:]
                            mname = mname[:arrayBegin]
                        self.debug("MEMBER (%s)" % match.group())
                        appendMember(mname, mtype, currentAccess, match.group(), mflags)
                elif item == self.re_typedef:
                    bits = [b for b in match.group()[:-1].split(" ") if b]
                    klass.typedef[bits[-1]] = " ".join(bits[1:-1])
                elif item == self.re_spuriousSemicolon:
                    pass
                else:
                    self.debug("NO_ACTION %s %s"% (match.group(), item))
                lastParsed = item

                oldBodyLength = len(body)
                if newbody:
                    body = newbody
                else:
                    body = body[match.span()[1]:]
                if len(body) >= oldBodyLength:
                    raise ("*** Breaking from infinite loop ***\n" \
                        "While parsing '%s'\n" \
                        "'%s'" % (klass.name, body) )
            return txt[classEnd:], klass
        else:
            self.debug("FORWARD (%s) (%s) (%s) (%s)" % (match.group("type"), match.group("namespace"), match.group("name"), match.group("parents")))
        return None, None