#!/usr/bin/env python
##########################################################################
#
-# Copyright 2011 Jose Fonseca
+# Copyright 2011-2012 Jose Fonseca
# All Rights Reserved.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
import difflib
+import itertools
import optparse
import os.path
import subprocess
import sys
-from unpickle import Unpickler
+from unpickle import Unpickler, Dumper
from highlight import ColorHighlighter, LessHighlighter
self.callNos = callNos
self.aSpace = 0
self.bSpace = 0
+ self.dumper = Dumper()
def diff(self):
matcher = difflib.SequenceMatcher(self.isjunk, self.a, self.b)
def replace_value(self, a, b):
if b == a:
- self.highlighter.write(str(b))
+ self.highlighter.write(self.dumper.visit(b))
else:
self.highlighter.strike()
self.highlighter.color(self.delete_color)
- self.highlighter.write(str(a))
+ self.highlighter.write(self.dumper.visit(a))
self.highlighter.normal()
self.highlighter.write(" ")
self.highlighter.color(self.insert_color)
- self.highlighter.write(str(b))
+ self.highlighter.write(self.dumper.visit(b))
self.highlighter.normal()
escape = "\33["
self.highlighter.bold(True)
self.highlighter.write(call.functionName)
self.highlighter.bold(False)
- self.highlighter.write('(' + ', '.join(map(repr, call.args)) + ')')
+ self.highlighter.write('(' + ', '.join(itertools.imap(self.dumper.visit, call.args)) + ')')
if call.ret is not None:
- self.highlighter.write(' = ' + repr(call.ret))
+ self.highlighter.write(' = ' + self.dumper.visit(call.ret))
self.highlighter.normal()
self.highlighter.write('\n')
'''
+import itertools
import optparse
-import cPickle as pickle
import sys
import time
+import re
+import cPickle as pickle
+
+
+class Visitor:
+
+ def __init__(self):
+ self.dispatch = {}
+ self.dispatch[type(None)] = self.visitNone
+ self.dispatch[bool] = self.visitBool
+ self.dispatch[int] = self.visitInt
+ self.dispatch[long] = self.visitInt
+ self.dispatch[float] = self.visitFloat
+ self.dispatch[str] = self.visitStr
+ self.dispatch[tuple] = self.visitTuple
+ self.dispatch[list] = self.visitList
+ self.dispatch[dict] = self.visitDict
+ self.dispatch[bytearray] = self.visitByteArray
+
+ def visit(self, obj, *args, **kwargs):
+ return self.dispatch[type(obj)](obj, *args, **kwargs)
+
+ def visitAtom(self, obj, *args, **kwargs):
+ raise NotImplementedError
+
+ def visitNone(self, obj, *args, **kwargs):
+ return self.visitAtom(obj, *args, **kwargs)
+
+ def visitBool(self, obj, *args, **kwargs):
+ return self.visitAtom(obj, *args, **kwargs)
+
+ def visitInt(self, obj, *args, **kwargs):
+ return self.visitAtom(obj, *args, **kwargs)
+
+ def visitFloat(self, obj, *args, **kwargs):
+ return self.visitAtom(obj, *args, **kwargs)
+
+ def visitStr(self, obj, *args, **kwargs):
+ return self.visitAtom(obj, *args, **kwargs)
+
+ def visitIterable(self, obj, *args, **kwargs):
+ raise NotImplementedError
+
+ def visitTuple(self, obj, *args, **kwargs):
+ return self.visitIterable(obj, *args, **kwargs)
+
+ def visitList(self, obj, *args, **kwargs):
+ return self.visitIterable(obj, *args, **kwargs)
+
+ def visitDict(self, obj, *args, **kwargs):
+ raise NotImplementedError
+
+ def visitByteArray(self, obj, *args, **kwargs):
+ raise NotImplementedError
+
+
+class Dumper(Visitor):
+
+ id_re = re.compile('^[_A-Za-z][_A-Za-z0-9]*$')
+
+ def visitAtom(self, obj, *args, **kwargs):
+ return repr(obj)
+
+ def visitStr(self, obj, *args, **kwargs):
+ if self.id_re.match(obj):
+ return obj
+ else:
+ return repr(obj)
+
+ def visitTuple(self, obj, *args, **kwargs):
+ return '[' + ', '.join(itertools.imap(self.visit, obj)) + ']'
+
+ def visitList(self, obj, *args, **kwargs):
+ return '(' + ', '.join(itertools.imap(self.visit, obj)) + ')'
+
+ def visitByteArray(self, obj, *args, **kwargs):
+ return 'blob(%u)' % len(obj)
+
+
+class Hasher(Visitor):
+ '''Returns a hashable version of the objtree.'''
+
+ def visitAtom(self, obj, *args, **kwargs):
+ return obj
+
+ def visitIterable(self, obj, *args, **kwargs):
+ return tuple(itertools.imap(self.visit, obj))
+
+ def visitByteArray(self, obj, *args, **kwargs):
+ return str(obj)
class Call:
s = self.functionName
if self.no is not None:
s = str(self.no) + ' ' + s
- s += '(' + ', '.join(map(repr, self.args)) + ')'
+ dumper = Dumper()
+ s += '(' + ', '.join(itertools.imap(dumper.visit, self.args)) + ')'
if self.ret is not None:
s += ' = '
- s += repr(self.ret)
+ s += dumper.visit(self.ret)
return s
def __eq__(self, other):
def __hash__(self):
if self._hash is None:
- # XXX: hack due to unhashable types
- #self._hash = hash(self.functionName) ^ hash(tuple(self.args)) ^ hash(self.ret)
- self._hash = hash(self.functionName) ^ hash(repr(self.args)) ^ hash(repr(self.ret))
+ hasher = Hasher()
+ hashable = hasher.visit(self.functionName), hasher.visit(self.args), hasher.visit(self.ret)
+ self._hash = hash(hashable)
return self._hash