Exemple #1
0
def replace_ors(node):
    """Replace all occurances of "or" with calls to "__logor__"."""
    if node.__class__ == Or:
        # Or nodes can contain 2 or more nodes, we have to handle them all. We
        # also have to respect the premature optimisation that if any is True
        # then the rest aren't evaluated. Thus the expression a or b or c or d
        # cannot be turned into simply a.__logor__(b).__logor__(c).__logor__(d)
        # because this will evaluate them all. Instead we need to pass in the
        # expressions as strings, and eval them if needed, so our call becomes
        # a.__logor__('''b.__logor__("""c.__logor__('d')""")''')

        # We replace Ors recursively. If there's only 2 nodes to compare then
        # we convert the first to a boolean, then recurse our tree
        # transformations through the second node, then pretty print the result
        # into a string which we wrap with a Const node and pass into a method
        # call of __logor__ on the boolean of the first node
        from python_rewriter.base import grammar
        if len(node.nodes) == 2:
            matcher = grammar([apply(node.nodes[-1])])
            return CallFunc(Getattr(CallFunc(Name('bool'),[node.nodes[0]]), \
             Name('__logor__')), [Const(matcher.apply('thing',0))])
        # Otherwise we build a nested series of ors (ie. "a or b or c or d"
        # becomes "a or (b or (c or d))") which we do recursively, and then we
        # apply ourselves to it recursively to complete the translation
        else:
            matcher = grammar([apply(Or(node.nodes[1:]))])
            return CallFunc(Getattr(CallFunc(Name('bool'),[node.nodes[0]]), \
             Name('__logor__')), [Const(matcher.apply('thing',0))])
    else:
        # If we've not got an Or node then simply recurse
        try:
            # map our transformation to members of any lists or tuples
            if type(node) in [type([]), type((0, 1))]:
                return map(replace_ors, node)
            # Stmt nodes are weird: their contents is [nodes] but asList only
            # gives nodes, breaking the *varargs technique used below
            if node.__class__ == Stmt:
                return Stmt(map(replace_ors, node.asList()))
            # If we're not in a list or Stmt, return a new instance of our
            # class, with transformed children
            return node.__class__(*map(replace_ors, node.asList()))
        except:
            # If an error occurs it's because strings, numbers, None, etc. don't
            # have an asList method. Since they're leaves, just return them.
            return node
def replace_ors(node):
	"""Replace all occurances of "or" with calls to "__logor__"."""
	if node.__class__ == Or:
		# Or nodes can contain 2 or more nodes, we have to handle them all. We
		# also have to respect the premature optimisation that if any is True
		# then the rest aren't evaluated. Thus the expression a or b or c or d
		# cannot be turned into simply a.__logor__(b).__logor__(c).__logor__(d)
		# because this will evaluate them all. Instead we need to pass in the
		# expressions as strings, and eval them if needed, so our call becomes
		# a.__logor__('''b.__logor__("""c.__logor__('d')""")''')

		# We replace Ors recursively. If there's only 2 nodes to compare then
		# we convert the first to a boolean, then recurse our tree
		# transformations through the second node, then pretty print the result
		# into a string which we wrap with a Const node and pass into a method
		# call of __logor__ on the boolean of the first node
		from python_rewriter.base import grammar
		if len(node.nodes) == 2:
			matcher = grammar([apply(node.nodes[-1])])
			return CallFunc(Getattr(CallFunc(Name('bool'),[node.nodes[0]]), \
				Name('__logor__')), [Const(matcher.apply('thing',0))])
		# Otherwise we build a nested series of ors (ie. "a or b or c or d"
		# becomes "a or (b or (c or d))") which we do recursively, and then we
		# apply ourselves to it recursively to complete the translation
		else:
			matcher = grammar([apply(Or(node.nodes[1:]))])
			return CallFunc(Getattr(CallFunc(Name('bool'),[node.nodes[0]]), \
				Name('__logor__')), [Const(matcher.apply('thing',0))])
	else:
		# If we've not got an Or node then simply recurse
		try:
			# map our transformation to members of any lists or tuples
			if type(node) in [type([]), type((0,1))]:
				return map(replace_ors, node)
			# Stmt nodes are weird: their contents is [nodes] but asList only
			# gives nodes, breaking the *varargs technique used below
			if node.__class__ == Stmt:
				return Stmt(map(replace_ors, node.asList()))
			# If we're not in a list or Stmt, return a new instance of our
			# class, with transformed children
			return node.__class__(*map(replace_ors, node.asList()))
		except:
			# If an error occurs it's because strings, numbers, None, etc. don't
			# have an asList method. Since they're leaves, just return them.
			return node
Exemple #3
0
def replace_ands(node):
    """Replace all occurances of "and" with calls to "__logand__"."""
    if node.__class__ == And:
        # We've got to be careful that we don't evaluate any expressions after
        # one which returns False, since this would break existing code that
        # depends on the assumption that such expressions will not be evaluated

        # If we have exactly 2 expressions then we simply build a string out of
        # the second and send it to the boolean value of the first, which will
        # presumably eval it if needed
        from python_rewriter.base import grammar
        if len(node.nodes) == 2:
            matcher = grammar([apply(node.nodes[-1])])
            return CallFunc(
                Getattr(CallFunc(Name('bool'), node.nodes[0]),
                        Name('__logand__')),
                [Const(matcher.apply('thing', 0))])
        else:
            matcher = grammar([apply(And(node.nodes[1:])).rec(0)])
            return CallFunc(
                Getattr(CallFunc(Name('bool'), node.nodes[0]),
                        Name('__logand__')),
                [Const(matcher.apply('thing', 0))])
    else:
        # If we've not got an And node then simply recurse
        try:
            # map our transformation to members of any lists or tuples
            if type(node) in [type([]), type((0, 1))]:
                return map(replace_ands, node)
            # Stmt nodes are weird: their contents is [nodes] but asList only
            # gives nodes, breaking the *varargs technique used below
            if node.__class__ == Stmt:
                return Stmt(map(replace_ands, node.asList()))
            # If we're not in a list or Stmt, return a new instance of our
            # class, with transformed children
            return node.__class__(*map(replace_ands, node.asList()))
        except:
            # If an error occurs it's because strings, numbers, None, etc. don't
            # have an asList method. Since they're leaves, just return them.
            return node
def replace_ands(node):
	"""Replace all occurances of "and" with calls to "__logand__"."""
	if node.__class__ == And:
		# We've got to be careful that we don't evaluate any expressions after
		# one which returns False, since this would break existing code that
		# depends on the assumption that such expressions will not be evaluated

		# If we have exactly 2 expressions then we simply build a string out of
		# the second and send it to the boolean value of the first, which will
		# presumably eval it if needed
		from python_rewriter.base import grammar
		if len(node.nodes) == 2:
			matcher = grammar([apply(node.nodes[-1])])
			return CallFunc(Getattr(CallFunc(Name('bool'),node.nodes[0]),
				Name('__logand__')), [Const(matcher.apply('thing',0))])
		else:
			matcher = grammar([apply(And(node.nodes[1:])).rec(0)])
			return CallFunc(Getattr(CallFunc(Name('bool'),node.nodes[0]),
				Name('__logand__')), [Const(matcher.apply('thing',0))])
	else:
		# If we've not got an And node then simply recurse
		try:
			# map our transformation to members of any lists or tuples
			if type(node) in [type([]), type((0,1))]:
				return map(replace_ands, node)
			# Stmt nodes are weird: their contents is [nodes] but asList only
			# gives nodes, breaking the *varargs technique used below
			if node.__class__ == Stmt:
				return Stmt(map(replace_ands, node.asList()))
			# If we're not in a list or Stmt, return a new instance of our
			# class, with transformed children
			return node.__class__(*map(replace_ands, node.asList()))
		except:
			# If an error occurs it's because strings, numbers, None, etc. don't
			# have an asList method. Since they're leaves, just return them.
			return node
def translate(path_or_text, initial_indent=0):
    """This performs the translation from Python to Diet Python. It
	takes in Python code (assuming the string to be a file path, falling
	back to treating it as Python code if it is not a valid path) and
	emits Diet Python code."""
    # See if the given string is a valid path
    if os.path.exists(path_or_text):
        # If so then open it and read the file contents into in_text
        infile = open(path_or_text, "r")
        in_text = "\n".join([line for line in infile.readlines()])
        infile.close()
        # Otherwise take the string contents to be in_text
    else:
        in_text = path_or_text

        # Wrap in try/except to give understandable error messages (PyMeta's
        # are full of obscure implementation details)
    try:
        # Get an Abstract Syntax Tree for the contents of in_text
        tree = parse(in_text)

        # Transform the Python AST into a Diet Python AST
        diet_tree = apply(tree)
        # print str(tree)
        # print str(diet_tree)

        # Generate (Diet) Python code to match the transformed tree
        from python_rewriter.base import grammar

        matcher = grammar([diet_tree])
        diet_code, err = matcher.apply("thing", initial_indent)

        # print str(tree)
        # print
        # print str(diet_tree)
        # print

        return diet_code

    except Exception, e:
        sys.stderr.write(str(e) + "\n")
        sys.stderr.write("Unable to translate.\n")
        sys.exit(1)
Exemple #6
0
def translate(path_or_text, initial_indent=0):
    """This performs the translation from Python to Diet Python. It
	takes in Python code (assuming the string to be a file path, falling
	back to treating it as Python code if it is not a valid path) and
	emits Diet Python code."""
    # See if the given string is a valid path
    if os.path.exists(path_or_text):
        # If so then open it and read the file contents into in_text
        infile = open(path_or_text, 'r')
        in_text = '\n'.join([line for line in infile.readlines()])
        infile.close()
    # Otherwise take the string contents to be in_text
    else:
        in_text = path_or_text

    # Wrap in try/except to give understandable error messages (PyMeta's
    # are full of obscure implementation details)
    try:
        # Get an Abstract Syntax Tree for the contents of in_text
        tree = parse(in_text)

        # Transform the Python AST into a Diet Python AST
        diet_tree = apply(tree)
        #print str(tree)
        #print str(diet_tree)

        # Generate (Diet) Python code to match the transformed tree
        from python_rewriter.base import grammar
        matcher = grammar([diet_tree])
        diet_code, err = matcher.apply('thing', initial_indent)

        #print str(tree)
        #print
        #print str(diet_tree)
        #print

        return diet_code

    except Exception, e:
        sys.stderr.write(str(e) + '\n')
        sys.stderr.write('Unable to translate.\n')
        sys.exit(1)
Exemple #7
0
def comparison_to_and(node):
    """Turns a series of comparisons into a nested series of independent
	comparisons. The behaviour is similar to logical and, including the
	restriction that the expression on the right should not be evaluated unless
	the expression on the left is true. The difficulty is that each expression
	should only be evaluated once, if at all. Thus if we had a comparison like:
	a < b < c == d >= e < f
	We cannot rewrite this as a < b and b < c and c == d and d >= e and e < f
	since in the case that they are all true, the expressions b, c, d and e will
	all be evaluated twice. Thus we must rely on the comparison methods to
	handle these correctly, and pass the right-hand expressions as strings to be
	evaled as needed (otherwise they would be evaluated as they are passed to
	the function, which would break the restriction that they should only be
	evaluated when the expressions to their left are true).
	Thus we extend the comparison method signature with a list of expressions to
	evaluate in the case that their first one succeeds. This should be
	implemented recursively, popping the head off the list, evaluating it and
	storing the result in a temporary variable. We can then do 2 comparisons
	against the temporary variable, which eliminates the need to evaluate the
	expressions twice. The tail of the list should be passed to this comparison
	so that it can recurse until it's empty.
	a.__lt__(b, [('__lt__','c'),('__eq__','d'),('__ge__','e'),('__lt__','f')])"""
    left = node.expr
    op = {'==':'__eq__', '!=':'__ne__', '>':'__gt__', '<':'__lt__', \
     '>=':'__ge__', '<=':'__le__'}[node.ops[0][0]]
    ops = [(op[a[0]], a[1]) for a in node.ops]
    if len(ops) == 1:
        return CallFunc(Getattr(apply(node.expr), Name(ops[0][0])),
                        [apply(ops[0][1])])
    else:
        first_op = ops.pop(0)
        from python_rewriter.base import grammar
        matcher = grammar([apply(a[1])])
        val, err = matcher.apply('thing', 0)
        return CallFunc(Getattr(apply(node.expr), Name(first_op[0])), \
         [apply(first_op[1]),List([ \
          Tuple([Const(a[0]),Const(val)]) for a in ops \
         ])] \
        )
def comparison_to_and(node):
    """Turns a series of comparisons into a nested series of independent
	comparisons. The behaviour is similar to logical and, including the
	restriction that the expression on the right should not be evaluated unless
	the expression on the left is true. The difficulty is that each expression
	should only be evaluated once, if at all. Thus if we had a comparison like:
	a < b < c == d >= e < f
	We cannot rewrite this as a < b and b < c and c == d and d >= e and e < f
	since in the case that they are all true, the expressions b, c, d and e will
	all be evaluated twice. Thus we must rely on the comparison methods to
	handle these correctly, and pass the right-hand expressions as strings to be
	evaled as needed (otherwise they would be evaluated as they are passed to
	the function, which would break the restriction that they should only be
	evaluated when the expressions to their left are true).
	Thus we extend the comparison method signature with a list of expressions to
	evaluate in the case that their first one succeeds. This should be
	implemented recursively, popping the head off the list, evaluating it and
	storing the result in a temporary variable. We can then do 2 comparisons
	against the temporary variable, which eliminates the need to evaluate the
	expressions twice. The tail of the list should be passed to this comparison
	so that it can recurse until it's empty.
	a.__lt__(b, [('__lt__','c'),('__eq__','d'),('__ge__','e'),('__lt__','f')])"""
    left = node.expr
    op = {"==": "__eq__", "!=": "__ne__", ">": "__gt__", "<": "__lt__", ">=": "__ge__", "<=": "__le__"}[node.ops[0][0]]
    ops = [(op[a[0]], a[1]) for a in node.ops]
    if len(ops) == 1:
        return CallFunc(Getattr(apply(node.expr), Name(ops[0][0])), [apply(ops[0][1])])
    else:
        first_op = ops.pop(0)
        from python_rewriter.base import grammar

        matcher = grammar([apply(a[1])])
        val, err = matcher.apply("thing", 0)
        return CallFunc(
            Getattr(apply(node.expr), Name(first_op[0])),
            [apply(first_op[1]), List([Tuple([Const(a[0]), Const(val)]) for a in ops])],
        )