Skip to main content
  • Home
  • Development
  • Documentation
  • Donate
  • Operational login
  • Browse the archive

swh logo
SoftwareHeritage
Software
Heritage
Archive
Features
  • Search

  • Downloads

  • Save code now

  • Add forge now

  • Help

Revision 1b57c8e01a682145f576e101c868ba84ea38ec1b authored by ah744 on 06 August 2016, 01:41:28 UTC, committed by ah744 on 06 August 2016, 01:41:28 UTC
Fixed Rotation Decomposition Naming and BF Type Mismatch
1 parent 2eae3de
  • Files
  • Changes
  • 0c74162
  • /
  • clang
  • /
  • utils
  • /
  • token-delta.py
Raw File Download

To reference or cite the objects present in the Software Heritage archive, permalinks based on SoftWare Hash IDentifiers (SWHIDs) must be used.
Select below a type of object currently browsed in order to display its associated SWHID and permalink.

  • revision
  • directory
  • content
revision badge
swh:1:rev:1b57c8e01a682145f576e101c868ba84ea38ec1b
directory badge
swh:1:dir:71f289464edb10a7ce95933f4968a5be3132032e
content badge
swh:1:cnt:327fa9221f0556dc59f6864710a26a39e953cc1f

This interface enables to generate software citations, provided that the root directory of browsed objects contains a citation.cff or codemeta.json file.
Select below a type of object currently browsed in order to generate citations for them.

  • revision
  • directory
  • content
(requires biblatex-software package)
Generating citation ...
(requires biblatex-software package)
Generating citation ...
(requires biblatex-software package)
Generating citation ...
token-delta.py
#!/usr/bin/env python

import os
import re
import subprocess
import sys
import tempfile

###

class DeltaAlgorithm(object):
    def __init__(self):
        self.cache = set()

    def test(self, changes):
        abstract

    ###

    def getTestResult(self, changes):
        # There is no reason to cache successful tests because we will
        # always reduce the changeset when we see one.

        changeset = frozenset(changes)
        if changeset in self.cache:
            return False
        elif not self.test(changes):
            self.cache.add(changeset)
            return False
        else:
            return True

    def run(self, changes, force=False):
        # Make sure the initial test passes, if not then (a) either
        # the user doesn't expect monotonicity, and we may end up
        # doing O(N^2) tests, or (b) the test is wrong. Avoid the
        # O(N^2) case unless user requests it.
        if not force:
            if not self.getTestResult(changes):
                raise ValueError,'Initial test passed to delta fails.'

        # Check empty set first to quickly find poor test functions.
        if self.getTestResult(set()):
            return set()
        else:
            return self.delta(changes, self.split(changes))

    def split(self, S):
        """split(set) -> [sets]

        Partition a set into one or two pieces.
        """

        # There are many ways to split, we could do a better job with more
        # context information (but then the API becomes grosser).
        L = list(S)
        mid = len(L)//2
        if mid==0:
            return L,
        else:
            return L[:mid],L[mid:]
    
    def delta(self, c, sets):
        # assert(reduce(set.union, sets, set()) == c)

        # If there is nothing left we can remove, we are done.
        if len(sets) <= 1:
            return c
        
        # Look for a passing subset.
        res = self.search(c, sets)
        if res is not None:
            return res

        # Otherwise, partition sets if possible; if not we are done.
        refined = sum(map(list, map(self.split, sets)), [])
        if len(refined) == len(sets):
            return c
        
        return self.delta(c, refined)

    def search(self, c, sets):
        for i,S in enumerate(sets):
            # If test passes on this subset alone, recurse.
            if self.getTestResult(S):
                return self.delta(S, self.split(S))

            # Otherwise if we have more than two sets, see if test
            # pases without this subset.
            if len(sets) > 2:
                complement = sum(sets[:i] + sets[i+1:],[])
                if self.getTestResult(complement):
                    return self.delta(complement, sets[:i] + sets[i+1:])

###

class Token:
    def __init__(self, type, data, flags, file, line, column):
        self.type   = type
        self.data   = data
        self.flags  = flags
        self.file   = file
        self.line   = line
        self.column = column
        
kTokenRE = re.compile(r"""([a-z_]+) '(.*)'\t(.*)\tLoc=<(.*):(.*):(.*)>""",
                      re.DOTALL | re.MULTILINE)

def getTokens(path):
    p = subprocess.Popen(['clang','-dump-raw-tokens',path],
                         stdin=subprocess.PIPE,
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE)
    out,err = p.communicate()

    tokens = []
    collect = None
    for ln in err.split('\n'):
        # Silly programmers refuse to print in simple machine readable
        # formats. Whatever.
        if collect is None:
            collect = ln
        else:
            collect = collect + '\n' + ln
        if 'Loc=<' in ln and ln.endswith('>'):
            ln,collect = collect,None
            tokens.append(Token(*kTokenRE.match(ln).groups()))

    return tokens

###

class TMBDDelta(DeltaAlgorithm):
    def __init__(self, testProgram, tokenLists, log):
        def patchName(name, suffix):
            base,ext = os.path.splitext(name)
            return base + '.' + suffix + ext
        super(TMBDDelta, self).__init__()
        self.testProgram = testProgram
        self.tokenLists = tokenLists
        self.tempFiles = [patchName(f,'tmp')
                            for f,_ in self.tokenLists]
        self.targetFiles = [patchName(f,'ok')
                            for f,_ in self.tokenLists]
        self.log = log
        self.numTests = 0

    def writeFiles(self, changes, fileNames):
        assert len(fileNames) == len(self.tokenLists)
        byFile = [[] for i in self.tokenLists]
        for i,j in changes:
            byFile[i].append(j)

        for i,(file,tokens) in enumerate(self.tokenLists):
            f = open(fileNames[i],'w')
            for j in byFile[i]:
                f.write(tokens[j])
            f.close()

        return byFile

    def test(self, changes):
        self.numTests += 1

        byFile = self.writeFiles(changes, self.tempFiles)

        if self.log:
            print >>sys.stderr, 'TEST - ',
            if self.log > 1:
                for i,(file,_) in enumerate(self.tokenLists):
                    indices = byFile[i]
                    if i:
                        sys.stderr.write('\n      ')
                    sys.stderr.write('%s:%d tokens: [' % (file,len(byFile[i])))
                    prev = None
                    for j in byFile[i]:
                        if prev is None or j != prev + 1:
                            if prev:
                                sys.stderr.write('%d][' % prev)
                            sys.stderr.write(str(j))
                            sys.stderr.write(':')
                        prev = j
                    if byFile[i]:
                        sys.stderr.write(str(byFile[i][-1]))
                    sys.stderr.write('] ')
            else:
                print >>sys.stderr, ', '.join(['%s:%d tokens' % (file, len(byFile[i]))
                                               for i,(file,_) in enumerate(self.tokenLists)]),

        p = subprocess.Popen([self.testProgram] + self.tempFiles)
        res = p.wait() == 0

        if res:
            self.writeFiles(changes, self.targetFiles)

        if self.log:
            print >>sys.stderr, '=> %s' % res
        else:
            if res:
                print '\nSUCCESS (%d tokens)' % len(changes)
            else:                
                sys.stderr.write('.')

        return res

    def run(self):
        res = super(TMBDDelta, self).run([(i,j)
                                          for i,(file,tokens) in enumerate(self.tokenLists)
                                          for j in range(len(tokens))])
        self.writeFiles(res, self.targetFiles)
        if not self.log:
            print >>sys.stderr
        return res

def tokenBasedMultiDelta(program, files, log):            
    # Read in the lists of tokens.
    tokenLists = [(file, [t.data for t in getTokens(file)])
                  for file in files]

    numTokens = sum([len(tokens) for _,tokens in tokenLists])
    print "Delta on %s with %d tokens." % (', '.join(files), numTokens)
    
    tbmd = TMBDDelta(program, tokenLists, log)

    res = tbmd.run()

    print "Finished %s with %d tokens (in %d tests)." % (', '.join(tbmd.targetFiles),
                                                         len(res),
                                                         tbmd.numTests)
        
def main():
    from optparse import OptionParser, OptionGroup
    parser = OptionParser("%prog <test program> {files+}")
    parser.add_option("", "--debug", dest="debugLevel",
                     help="set debug level [default %default]",
                     action="store", type=int, default=0)
    (opts, args) = parser.parse_args()

    if len(args) <= 1:
        parser.error('Invalid number of arguments.')
        
    program,files = args[0],args[1:]

    md = tokenBasedMultiDelta(program, files, log=opts.debugLevel)
        
if __name__ == '__main__':
    try:
        main()
    except KeyboardInterrupt:
        print >>sys.stderr,'Interrupted.'
        os._exit(1) # Avoid freeing our giant cache.
The diff you're trying to view is too large. Only the first 1000 changed files have been loaded.
Showing with 0 additions and 0 deletions (0 / 0 diffs computed)
swh spinner

Computing file changes ...

back to top

Software Heritage — Copyright (C) 2015–2026, The Software Heritage developers. License: GNU AGPLv3+.
The source code of Software Heritage itself is available on our development forge.
The source code files archived by Software Heritage are available under their own copyright and licenses.
Terms of use: Archive access, API— Content policy— Contact— JavaScript license information— Web API