def reduceOperation(literalNode): resultNode = literalNode treeModified = False # can only reduce with constants if literalNode.type != "constant": return literalNode, False # check if we're in an operation ngParent = nextNongroupParent(literalNode) # could be operand in ops if not ngParent or ngParent.type != "operation": return literalNode, False else: operationNode = ngParent # try to evaluate expr operationNode = evaluate.evaluate(operationNode) if operationNode.evaluated != (): # we have a value # create replacement resultNode = symbol("constant")(operationNode.get("line"), operationNode.get("column")) resultNode = set_node_type_from_value(resultNode, operationNode.evaluated) # modify tree operationNode.parent.replaceChild(operationNode, resultNode) treeModified = True return resultNode, treeModified
def prefix(id_): def format(self, optns, state): r = self.commentsPretty(optns, state) r += self.get("value") r += self.getChild("first").format(optns, state) return r symbol(id_).format = format
def reduceOperation(literalNode): resultNode = literalNode treeModified = False # can only reduce with constants if literalNode.type != "constant": return literalNode, False # check if we're in an operation ngParent = nextNongroupParent(literalNode) # could be operand in ops if not ngParent or ngParent.type != "operation": return literalNode, False else: operationNode = ngParent # try to evaluate expr operationNode = evaluate.evaluate(operationNode) if operationNode.evaluated != (): # we have a value # create replacement resultNode = symbol("constant")( operationNode.get("line"), operationNode.get("column")) resultNode = set_node_type_from_value(resultNode, operationNode.evaluated) # modify tree operationNode.parent.replaceChild(operationNode, resultNode) treeModified = True return resultNode, treeModified
def reduceCall(callNode, value): # construct the value node valueNode = symbol("constant")(callNode.get("line"), callNode.get("column")) valueNode.set("value", str(value)) if isinstance(value, types.StringTypes): valueNode.set("constantType", "string") valueNode.set("detail", "doublequotes") # this has to come first, as isinstance(True, types.IntType) is also true! elif isinstance(value, types.BooleanType): valueNode.set("constantType", "boolean") valueNode.set("value", str(value).lower()) elif isinstance(value, types.IntType): valueNode.set("constantType", "number") valueNode.set("detail", "int") elif isinstance(value, types.FloatType): valueNode.set("constantType", "number") valueNode.set("detail", "float") elif isinstance(value, types.NoneType): valueNode.set("constantType", "null") valueNode.set("value", "null") else: raise ValueError("Illegal value for JS constant: %s" % str(value)) # put it in place of the callNode #print "optimizing: .get()" callNode.parent.replaceChild(callNode, valueNode) return valueNode
def prefix(id_): def visit_(self, optns, state): r = self.commentsPretty(self.comments, optns, state) r += self.get("value") r += self.getChild(0).format(optns, state) return r symbol(id_).format = format
def prefix(id_): def toPretty(self, optns, state): r = u'' r += self.get("value") r += self.getChild("first").toPretty(optns, state) return r symbol(id_).toPretty = toPretty
def reduceCall(callNode, value): # construct the value node valueNode = symbol("constant")( callNode.get("line"), callNode.get("column")) valueNode.set("value", str(value)) if isinstance(value, types.StringTypes): valueNode.set("constantType","string") valueNode.set("detail", "doublequotes") # this has to come first, as isinstance(True, types.IntType) is also true! elif isinstance(value, types.BooleanType): valueNode.set("constantType","boolean") valueNode.set("value", str(value).lower()) elif isinstance(value, types.IntType): valueNode.set("constantType","number") valueNode.set("detail", "int") elif isinstance(value, types.FloatType): valueNode.set("constantType","number") valueNode.set("detail", "float") elif isinstance(value, types.NoneType): valueNode.set("constantType","null") valueNode.set("value", "null") else: raise ValueError("Illegal value for JS constant: %s" % str(value)) # put it in place of the callNode #print "optimizing: .get()" callNode.parent.replaceChild(callNode, valueNode) return valueNode
def visit_ArrayExpression(self, enode): # array literal n = new_symbol("array", enode) for child in enode["elements"]: if child is None: n.childappend(symbol("(empty)")()) else: n.childappend(self.visit_Expression(child)) return n
def prefix_v(id_): def toPretty(self, optns, state): r = self.commentsPretty(optns, state) r += self.get("value") r += self.space() r += self.getChild("first").toPretty(optns, state) return r symbol(id_).toPretty = toPretty
def prefix(id_): def format(self, optns, state): r = self.commentsPretty(optns, state) r += self.get("value") r += self.getChild(0).format(optns, state) return r symbol(id_).format = format
def reduceCall(callNode, value): # construct the value node valueNode = symbol("constant")(callNode.get("line"), callNode.get("column")) valueNode = reducer.set_node_type_from_value(valueNode, value) # put it in place of the callNode # print "optimizing: .get()" callNode.parent.replaceChild(callNode, valueNode) return valueNode
def prefix_v(id_): def format(self, optns, state): r = self.commentsPretty(optns, state) r += self.get("value") r += self.space() r += self.getChild(0).format(optns, state) return r symbol(id_).format = format
def reduceCall(callNode, value): # construct the value node valueNode = symbol("constant")(callNode.get("line"), callNode.get("column")) valueNode = reducer.set_node_type_from_value(valueNode, value) # put it in place of the callNode #print "optimizing: .get()" callNode.parent.replaceChild(callNode, valueNode) return valueNode
def prefix_v(id_): def visit_(self, optns, state): r = self.commentsPretty(self.comments, optns, state) r += self.get("value") r += self.space() r += self.getChild(0).format(optns, state) return r symbol(id_).format = format
def infix(id_): def format(self, optns, state): r = self.commentsPretty(optns, state) r += self.getChild(0).format(optns, state) r += ' ' r += self.get("value") r += ' ' r += self.getChild(1).format(optns, state) return r symbol(id_).format = format
def infix_v(id_): def visit_(self, optns, state): # adapt the output r = self.commentsPretty(self.comments, optns, state) r += self.getChild(0).format(optns, state) r += self.space() r += self.get("value") r += self.space() r += self.getChild(1).format(optns, state) return r symbol(id_).format = format
def infix(id_): def toPretty(self, optns, state): r = self.commentsPretty(optns, state) r += self.getChild("first").toPretty(optns, state) r += ' ' r += self.get("value") r += ' ' r += self.getChild("second").toPretty(optns, state) return r symbol(id_).toPretty = toPretty
def infix_v(id_): def toPretty(self, optns, state): # adapt the output r = u'' r += self.getChild("first").toPretty(optns, state) r += self.space() r += self.get("value") r += self.space() r += self.getChild("second").toPretty(optns, state) return r symbol(id_).toPretty = toPretty
def infix_v(id_): def format(self, optns, state): # adapt the output r = self.commentsPretty(optns, state) r += self.getChild("first").format(optns, state) r += self.space() r += self.get("value") r += self.space() r += self.getChild("second").format(optns, state) return r symbol(id_).format = format
def infix_v(id_): def format(self, optns, state): # adapt the output r = self.commentsPretty(optns, state) r += self.getChild(0).format(optns, state) r += self.space() r += self.get("value") r += self.space() r += self.getChild(1).format(optns, state) return r symbol(id_).format = format
def _visit_monadic(self, node, operator): op1 = node.children[0] nnode = node if hasattr(op1, "evaluated"): if operator in self.operations: evaluated = self.operations[operator](op1.evaluated) nnode = symbol("constant")( node.get("line"), node.get("column")) set_node_type_from_value(nnode, evaluated) nnode.evaluated = evaluated return nnode
def infix(id_): def visit_(self, optns, state): r = self.commentsPretty(self.comments, optns, state) r += self.getChild(0).format(optns, state) r += ' ' r += self.get("value") r += ' ' r += self.getChild(1).format(optns, state) return r symbol(id_).format = format
def _visit_monadic(self, node, operator): op1 = node.children[0] nnode = node if hasattr(op1, "evaluated"): if operator in self.operations: evaluated = self.operations[operator](op1.evaluated) if evaluated != (): nnode = symbol("constant")(node.get("line"), node.get("column")) set_node_type_from_value(nnode, evaluated) nnode.evaluated = evaluated return nnode
def prepostfix(id_): # pre-/post-fix operators (++, --) def format(self, optns, state): r = self.commentsPretty(optns, state) operator = self.get("value") operand = self.getChild("first").format(optns, state) r += self.get("value") if self.get("left", '') == "true": r = [operator, operand] else: r = [operand, operator] return u''.join(r) symbol(id_).format = format
def prepostfix(id_): # pre-/post-fix operators (++, --) def toPretty(self, optns, state): r = u'' operator = self.get("value") operand = self.getChild("first").toPretty(optns, state) r += self.get("value") if self.get("left", '') == "true": r = [operator, operand] else: r = [operand, operator] return u''.join(r) symbol(id_).toPretty = toPretty
def prepostfix(id_): # pre-/post-fix operators (++, --) def toPretty(self, optns, state): r = u"" operator = self.get("value") operand = self.getChild("first").toPretty(optns, state) r += self.get("value") if self.get("left", "") == "true": r = [operator, operand] else: r = [operand, operator] return u"".join(r) symbol(id_).toPretty = toPretty
def prepostfix(id_): # pre-/post-fix operators (++, --) def format(self, optns, state): r = self.commentsPretty(optns, state) operator = self.get("value") operand = self.getChild(0).format(optns, state) r += self.get("value") if self.get("left", '') == "true": r = [operator, operand] else: r = [operand, operator] return u''.join(r) symbol(id_).format = format
def preinfix(id_): # pre-/infix operators (+, -) def toPretty(self, optns, state): # need to handle pre/infix cases r = [] first = self.getChild("first").toPretty(optns, state) op = self.get("value") prefix = self.get("left", 0) if prefix and prefix == "true": r = [op, first] else: second = self.getChild("second").toPretty(optns, state) r = [first, op, second] return ''.join(r) symbol(id_).toPretty = toPretty
def preinfix(id_): # pre-/infix operators (+, -) def format(self, optns, state): # need to handle pre/infix cases r = self.commentsPretty(self.comments, optns, state) r = [r] first = self.getChild(0).format(optns, state) op = self.get("value") prefix = self.get("left", 0) if prefix and prefix == "true": r = [op, first] else: second = self.getChild(1).format(optns, state) r = [first, ' ', op, ' ', second] return ''.join(r) symbol(id_).format = format
def _visit_dyadic(self, node, operator): op1 = node.children[0] op2 = node.children[1] nnode = node if operator in self.operations: if operator in ['AND', 'OR'] and hasattr(op1, 'evaluated'): # short-circuit ops evaluated = self.operations[operator](op1.evaluated, op2) nnode = op1 if evaluated==op1.evaluated else op2 elif all([hasattr(x, 'evaluated') for x in (op1, op2)]): evaluated = self.operations[operator](op1.evaluated, op2.evaluated) nnode = symbol("constant")( node.get("line"), node.get("column")) set_node_type_from_value(nnode, evaluated) nnode.evaluated = evaluated return nnode
def preinfix(id_): # pre-/infix operators (+, -) def format(self, optns, state): # need to handle pre/infix cases r = self.commentsPretty(optns, state) r = [r] first = self.getChild(0).format(optns, state) op = self.get("value") prefix = self.get("left", 0) if prefix and prefix == "true": r = [op, first] else: second = self.getChild(1).format(optns, state) r = [first, ' ', op, ' ', second] return ''.join(r) symbol(id_).format = format
def _visit_dyadic(self, node, operator): op1 = node.children[0] op2 = node.children[1] nnode = node if operator in self.operations: if operator in ['AND', 'OR'] and hasattr( op1, 'evaluated'): # short-circuit ops evaluated = self.operations[operator](op1.evaluated, op2) nnode = op1 if evaluated == op1.evaluated else op2 elif all([hasattr(x, 'evaluated') for x in (op1, op2)]): evaluated = self.operations[operator](op1.evaluated, op2.evaluated) if evaluated != (): nnode = symbol("constant")(node.get("line"), node.get("column")) set_node_type_from_value(nnode, evaluated) nnode.evaluated = evaluated return nnode
def _rewrite_if(self, if_node, cond_val): if cond_val: # use then branch replacement = if_node.children[1] # rescue vardecl's from else branch, so these vars don't become global # if used elsewhere, but *don't* rescue their init's. if len(if_node.children) == 3: extracted_vars = extract_vars(if_node.children[2]) add_vars(replacement, extracted_vars) else: # use else branch or empty if len(if_node.children) == 3: replacement = if_node.children[2] else: # don't leave single-statement parent loops empty (if_node.parent.type not in ("block", "file") replacement = treegenerator.symbol("block")(if_node.get("line"), if_node.get("column")) # rescue vardecl's from then branch extracted_vars = extract_vars(if_node.children[1]) add_vars(replacement, extracted_vars) if_node.parent.replaceChild(if_node, replacement)
def _rewrite_if(self, if_node, cond_val): if cond_val: # use then branch replacement = if_node.children[1] # rescue vardecl's from else branch, so these vars don't become global # if used elsewhere, but *don't* rescue their init's. if len(if_node.children) == 3: extracted_vars = extract_vars(if_node.children[2]) add_vars(replacement, extracted_vars) else: # use else branch or empty if len(if_node.children) == 3: replacement = if_node.children[2] else: # don't leave single-statement parent loops empty (if_node.parent.type not in ("block", "file") replacement = treegenerator.symbol("block")( if_node.get("line"), if_node.get("column")) # rescue vardecl's from then branch extracted_vars = extract_vars(if_node.children[1]) add_vars(replacement, extracted_vars) if_node.parent.replaceChild(if_node, replacement)
def new_symbol(typ, enode): loc = enode['loc']['start'] n = symbol(typ)(loc['line'], loc['column'] + 1) return n
def reduceOperation(literalNode): resultNode = None treeModified = False # can only reduce with constants if literalNode.type != "constant": return literalNode, False else: literalValue = constNodeToPyValue(literalNode) # check if we're in an operation ngParent = nextNongroupParent(literalNode) # could be operand in ops if not ngParent or ngParent.type != "operation": return literalNode, False else: operationNode = ngParent # get operator operator = operationNode.get("operator") # normalize expression noperationNode = normalizeExpression(operationNode) # re-gain knownn literal node for node in treeutil.nodeIterator(noperationNode, [literalNode.type]): if literalNode.attributes == node.attributes: nliteralNode = node break # equal, unequal if operator in ["EQ", "SHEQ", "NE", "SHNE"]: otherOperand, _ = getOtherOperand(noperationNode, nliteralNode) if otherOperand.type != "constant": return literalNode, False if operator in ["EQ", "SHEQ"]: cmpFcn = operators.eq elif operator in ["NE", "SHNE"]: cmpFcn = operators.ne operands = [literalValue] otherVal = constNodeToPyValue(otherOperand) operands.append(otherVal) result = cmpFcn(operands[0], operands[1]) resultNode = symbol("constant")(noperationNode.get("line"), noperationNode.get("column")) resultNode.set("constantType", "boolean") resultNode.set("value", str(result).lower()) # order compares <, =<, ... elif operator in ["LT", "LE", "GT", "GE"]: otherOperand, otherPosition = getOtherOperand(noperationNode, nliteralNode) if otherOperand.type != "constant": return literalNode, False if operator == "LT": cmpFcn = operators.lt elif operator == "LE": cmpFcn = operators.le elif operator == "GT": cmpFcn = operators.gt elif operator == "GE": cmpFcn = operators.ge operands = {} operands[1 - otherPosition] = literalValue otherVal = constNodeToPyValue(otherOperand) operands[otherPosition] = otherVal result = cmpFcn(operands[0], operands[1]) resultNode = symbol("constant")(noperationNode.get("line"), noperationNode.get("column")) resultNode.set("constantType", "boolean") resultNode.set("value", str(result).lower()) # logical ! (not) elif operator in ["NOT"]: result = not literalValue resultNode = symbol("constant")(noperationNode.get("line"), noperationNode.get("column")) resultNode.set("constantType", "boolean") resultNode.set("value", str(result).lower()) # logical operators &&, || elif operator in ["AND", "OR"]: result = None otherOperand, otherPosition = getOtherOperand(noperationNode, nliteralNode) if operator == "AND": #if otherPosition==1 and not literalValue: # short circuit # result = False #else: cmpFcn = (lambda x, y: x and y) elif operator == "OR": #if otherPosition==1 and literalValue: # short circuit # result = True #else: cmpFcn = (lambda x, y: x or y) if result == None: if otherOperand.type != "constant": return literalNode, False operands = {} operands[1 - otherPosition] = literalValue otherVal = constNodeToPyValue(otherOperand) operands[otherPosition] = otherVal result = cmpFcn(operands[0], operands[1]) resultNode = { literalValue: literalNode, otherVal: otherOperand }[result] # hook ?: operator elif operator in ["HOOK"]: if ngParent == noperationNode.children[ 0]: # optimize a literal condition if bool(literalValue): resultNode = noperationNode.children[1] else: resultNode = noperationNode.children[2] # unsupported operation else: pass if resultNode != None: #print "optimizing: operation" operationNode.parent.replaceChild(operationNode, resultNode) treeModified = True else: resultNode = literalNode treeModified = False return resultNode, treeModified
r = self.commentsPretty(optns, state) operator = self.get("value") operand = self.getChild("first").format(optns, state) r += self.get("value") if self.get("left", '') == "true": r = [operator, operand] else: r = [operand, operator] return u''.join(r) symbol(id_).format = format for sym in SYMBOLS['prepostfix']: prepostfix(sym) @method(symbol("constant")) def format(self, optns, state): r = self.commentsPretty(optns, state) if self.get("constantType") == "string": if self.get("detail") == "singlequotes": r += self.write("'") else: r += self.write('"') r += self.write(self.get("value")) if self.get("detail") == "singlequotes": r += self.write("'") else: r += self.write('"') else: r += self.write(self.get("value")) return r
def reduceOperation(literalNode): resultNode = None treeModified = False # can only reduce with constants if literalNode.type != "constant": return literalNode, False else: literalValue = constNodeToPyValue(literalNode) # check if we're in an operation ngParent = nextNongroupParent(literalNode) # could be operand in ops if not ngParent or ngParent.type != "operation": return literalNode, False else: operationNode = ngParent # get operator operator = operationNode.get("operator") # normalize expression noperationNode = normalizeExpression(operationNode) # re-gain knownn literal node for node in treeutil.nodeIterator(noperationNode, [literalNode.type]): if literalNode.attributes == node.attributes: nliteralNode = node break # equal, unequal if operator in ["EQ", "SHEQ", "NE", "SHNE"]: otherOperand, _ = getOtherOperand(noperationNode, nliteralNode) if otherOperand.type != "constant": return literalNode, False if operator in ["EQ", "SHEQ"]: cmpFcn = operators.eq elif operator in ["NE", "SHNE"]: cmpFcn = operators.ne operands = [literalValue] otherVal = constNodeToPyValue(otherOperand) operands.append(otherVal) result = cmpFcn(operands[0],operands[1]) resultNode = symbol("constant")( noperationNode.get("line"), noperationNode.get("column")) resultNode.set("constantType","boolean") resultNode.set("value", str(result).lower()) # order compares <, =<, ... elif operator in ["LT", "LE", "GT", "GE"]: otherOperand, otherPosition = getOtherOperand(noperationNode, nliteralNode) if otherOperand.type != "constant": return literalNode, False if operator == "LT": cmpFcn = operators.lt elif operator == "LE": cmpFcn = operators.le elif operator == "GT": cmpFcn = operators.gt elif operator == "GE": cmpFcn = operators.ge operands = {} operands[1 - otherPosition] = literalValue otherVal = constNodeToPyValue(otherOperand) operands[otherPosition] = otherVal result = cmpFcn(operands[0], operands[1]) resultNode = symbol("constant")( noperationNode.get("line"), noperationNode.get("column")) resultNode.set("constantType","boolean") resultNode.set("value", str(result).lower()) # logical ! (not) elif operator in ["NOT"]: result = not literalValue resultNode = symbol("constant")( noperationNode.get("line"), noperationNode.get("column")) resultNode.set("constantType","boolean") resultNode.set("value", str(result).lower()) # logical operators &&, || elif operator in ["AND", "OR"]: result = None otherOperand, otherPosition = getOtherOperand(noperationNode, nliteralNode) if operator == "AND": #if otherPosition==1 and not literalValue: # short circuit # result = False #else: cmpFcn = (lambda x,y: x and y) elif operator == "OR": #if otherPosition==1 and literalValue: # short circuit # result = True #else: cmpFcn = (lambda x,y: x or y) if result == None: if otherOperand.type != "constant": return literalNode, False operands = {} operands[1 - otherPosition] = literalValue otherVal = constNodeToPyValue(otherOperand) operands[otherPosition] = otherVal result = cmpFcn(operands[0], operands[1]) resultNode = {literalValue:literalNode, otherVal:otherOperand}[result] # hook ?: operator elif operator in ["HOOK"]: if ngParent == noperationNode.children[0]: # optimize a literal condition if bool(literalValue): resultNode = noperationNode.children[1] else: resultNode = noperationNode.children[2] # unsupported operation else: pass if resultNode != None: #print "optimizing: operation" operationNode.parent.replaceChild(operationNode, resultNode) treeModified = True else: resultNode = literalNode treeModified = False return resultNode, treeModified
def inlineIfStatement(ifNode, conditionValue): """ Inline an if statement assuming that the condition of the if statement evaluates to "conditionValue" (True/False") """ if ifNode.type != "loop" or ifNode.get("loopType") != "IF": raise tree.NodeAccessException("Expected the LOOP node of an if statement!", mapNode) replacement = [] newDefinitions = [] removedDefinitions = [] if len(ifNode.children)==3: # there is an 'else' part if conditionValue: removedDefinitions = getDefinitions(ifNode.children[2]) newDefinitions = getDefinitions(ifNode.children[1]) replacement = ifNode.children[1].children[0] # <body>.children: single node, <block> or <statement> else: removedDefinitions = getDefinitions(ifNode.children[1]) newDefinitions = getDefinitions(ifNode.children[2]) replacement = ifNode.children[2].children[0] else: if conditionValue: newDefinitions = getDefinitions(ifNode.children[1]) replacement = ifNode.children[1].children[0] else: removedDefinitions = getDefinitions(ifNode.children[1]) newDefinitions = [x.getDefinee().get("value") for x in newDefinitions] definitions = [] for definition in removedDefinitions: if not definition.getDefinee().get("value") in newDefinitions: definitions.append(definition) if len(definitions) > 0: defList = treegenerator.symbol("var")() defList.set("line", ifNode.get("line")) defList.set("column", ifNode.get("column")) for definition in definitions: # remove initialisations if definition.children[0].type == "identifier": pass else: # assignment idf = definition.getDefinee() definition.children[0] = idf defList.addChild(definition) # move defList to higher node node = ifNode while node.type not in ("statements",): if node.parent: node = node.parent else: break node.addChild(defList,0) # move replacement if replacement: replaceChildWithNodes(ifNode.parent, ifNode, [replacement]) # helper expects list else: emptyBlock = treegenerator.symbol("block")() emptyBlock.set("line", ifNode.get("line")) # TODO: experimental bug#4734: is this enough? if (ifNode.parent.type in ["block", "file"]): ifNode.parent.removeChild(ifNode) else: # don't leave single-statement parent loops empty ifNode.parent.replaceChild(ifNode, emptyBlock) replacement = emptyBlock return replacement
operand = self.getChild("first").toPretty(optns, state) r += self.get("value") if self.get("left", '') == "true": r = [operator, operand] else: r = [operand, operator] return u''.join(r) symbol(id_).toPretty = toPretty for sym in SYMBOLS['prepostfix']: prepostfix(sym) @method(symbol("constant")) def toPretty(self, optns, state): r = self.commentsPretty(optns, state) if self.get("constantType") == "string": if self.get("detail") == "singlequotes": r += self.write("'") else: r += self.write('"') r += self.write(self.get("value")) if self.get("detail") == "singlequotes": r += self.write("'") else: r += self.write('"') else: r += self.write(self.get("value")) return r
def visit_EmptyStatement(self, enode): return symbol('(empty)')()
def new_symbol(typ, enode): loc = enode['loc']['start'] n = symbol(typ)(loc['line'], loc['column']+1) return n
def inlineIfStatement(ifNode, conditionValue): """ Inline an if statement assuming that the condition of the if statement evaluates to "conditionValue" (True/False") """ if ifNode.type != "loop" or ifNode.get("loopType") != "IF": raise tree.NodeAccessException("Expected the LOOP node of an if statement!", mapNode) replacement = [] newDefinitions = [] removedDefinitions = [] if len(ifNode.children)==3: # there is an 'else' part if conditionValue: removedDefinitions = getDefinitions(ifNode.children[2]) newDefinitions = getDefinitions(ifNode.children[1]) replacement = ifNode.children[1].children[0].children else: removedDefinitions = getDefinitions(ifNode.children[1]) newDefinitions = getDefinitions(ifNode.children[2]) replacement = ifNode.children[2].children[0].children else: if conditionValue: newDefinitions = getDefinitions(ifNode.children[1]) replacement = ifNode.children[1].children[0].children else: removedDefinitions = getDefinitions(ifNode.children[1]) newDefinitions = [x.getDefinee().get("value") for x in newDefinitions] definitions = [] for definition in removedDefinitions: if not definition.getDefinee().get("value") in newDefinitions: definitions.append(definition) if len(definitions) > 0: defList = treegenerator.symbol("var")() defList.set("line", ifNode.get("line")) defList.set("column", ifNode.get("column")) for definition in definitions: # remove initialisations if definition.children[0].type == "identifier": pass else: # assignment idf = definition.getDefinee() definition.children[0] = idf defList.addChild(definition) # move defList to higher node node = ifNode while node.type not in ("statements",): if node.parent: node = node.parent else: break node.addChild(defList,0) # move replacement if replacement: replacement = replacement[:] # retain copy for return value replaceChildWithNodes(ifNode.parent, ifNode, replacement) else: emptyBlock = treegenerator.symbol("block")() emptyBlock.set("line", ifNode.get("line")) # TODO: experimental bug#4734: is this enough? if (ifNode.parent.type in ["block", "file"]): ifNode.parent.removeChild(ifNode) else: # don't leave single-statement parent loops empty ifNode.parent.replaceChild(ifNode, emptyBlock) replacement = [emptyBlock] return replacement
def inlineIfStatement(ifNode, conditionValue, inPlace=True): """ Inline an if statement assuming that the condition of the if statement evaluates to "conditionValue" (True/False") """ if ifNode.type != "loop" or ifNode.get("loopType") != "IF": raise tree.NodeAccessException( "Expected the LOOP node of an if statement!", ifNode) replacement = None replacement_is_empty = False newDefinitions = [] removedDefinitions = [] if len(ifNode.children) == 3: # there is an 'else' part if conditionValue: removedDefinitions = getDefinitions(ifNode.children[2]) newDefinitions = getDefinitions(ifNode.children[1]) replacement = ifNode.children[1].children[ 0] # <body>.children: single node, <block> or <statement> else: removedDefinitions = getDefinitions(ifNode.children[1]) newDefinitions = getDefinitions(ifNode.children[2]) replacement = ifNode.children[2].children[0] else: if conditionValue: newDefinitions = getDefinitions(ifNode.children[1]) replacement = ifNode.children[1].children[0] else: removedDefinitions = getDefinitions(ifNode.children[1]) # don't leave single-statement parent loops empty emptyBlock = treegenerator.symbol("block")() emptyBlock.set("line", ifNode.get("line")) stmts = treegenerator.symbol("statements")() stmts.set("line", ifNode.get("line")) emptyBlock.addChild(stmts) replacement = emptyBlock replacement_is_empty = True # Rescue var decls newDefinitions = [x.getDefinee().get("value") for x in newDefinitions] definitions = [] for definition in removedDefinitions: if not definition.getDefinee().get("value") in newDefinitions: definitions.append(definition) if len(definitions) > 0: defList = treegenerator.symbol("var")() defList.set("line", ifNode.get("line")) defList.set("column", ifNode.get("column")) for definition in definitions: # remove initialisations if definition.children[0].type == "identifier": pass else: # assignment idf = definition.getDefinee() definition.children[0] = idf defList.addChild(definition) # attach defList to replacement if replacement.type != 'block': # treat single-statement branches block = treegenerator.symbol("block")() block.set("line", ifNode.get("line")) stmts = treegenerator.symbol("statements")() stmts.set("line", ifNode.get("line")) block.addChild(stmts) stmts.addChild(replacement) replacement = block replacement.getChild("statements").addChild(defList, 0) replacement_is_empty = False # move replacement if inPlace: if (replacement_is_empty and ifNode.parent.type in ["statements"]): ifNode.parent.removeChild(ifNode) else: ifNode.parent.replaceChild(ifNode, replacement) return replacement, replacement_is_empty
def inlineIfStatement(ifNode, conditionValue, inPlace=True): """ Inline an if statement assuming that the condition of the if statement evaluates to "conditionValue" (True/False") """ if ifNode.type != "loop" or ifNode.get("loopType") != "IF": raise tree.NodeAccessException("Expected the LOOP node of an if statement!", ifNode) replacement = None replacement_is_empty = False newDefinitions = [] removedDefinitions = [] if len(ifNode.children)==3: # there is an 'else' part if conditionValue: removedDefinitions = getDefinitions(ifNode.children[2]) newDefinitions = getDefinitions(ifNode.children[1]) replacement = ifNode.children[1].children[0] # <body>.children: single node, <block> or <statement> else: removedDefinitions = getDefinitions(ifNode.children[1]) newDefinitions = getDefinitions(ifNode.children[2]) replacement = ifNode.children[2].children[0] else: if conditionValue: newDefinitions = getDefinitions(ifNode.children[1]) replacement = ifNode.children[1].children[0] else: removedDefinitions = getDefinitions(ifNode.children[1]) # don't leave single-statement parent loops empty emptyBlock = treegenerator.symbol("block")() emptyBlock.set("line", ifNode.get("line")) stmts = treegenerator.symbol("statements")() stmts.set("line", ifNode.get("line")) emptyBlock.addChild(stmts) replacement = emptyBlock replacement_is_empty = True # Rescue var decls newDefinitions = [x.getDefinee().get("value") for x in newDefinitions] definitions = [] for definition in removedDefinitions: if not definition.getDefinee().get("value") in newDefinitions: definitions.append(definition) if len(definitions) > 0: defList = treegenerator.symbol("var")() defList.set("line", ifNode.get("line")) defList.set("column", ifNode.get("column")) for definition in definitions: # remove initialisations if definition.children[0].type == "identifier": pass else: # assignment idf = definition.getDefinee() definition.children[0] = idf defList.addChild(definition) # attach defList to replacement if replacement.type != 'block': # treat single-statement branches block = treegenerator.symbol("block")() block.set("line", ifNode.get("line")) stmts = treegenerator.symbol("statements")() stmts.set("line", ifNode.get("line")) block.addChild(stmts) stmts.addChild(replacement) replacement = block replacement.getChild("statements").addChild(defList,0) replacement_is_empty = False # move replacement if inPlace: if (replacement_is_empty and ifNode.parent.type in ["statements"]): ifNode.parent.removeChild(ifNode) else: ifNode.parent.replaceChild(ifNode, replacement) return replacement, replacement_is_empty
class Formatter(treeutil.NodeVisitor): def __init__(self, root_node, options, state): super(Formatter, self).__init__() self.root_node = root_node self.optns = options self.state = state def visit(self, node): r = [] r += [self.commentsPretty(node.comments)] if hasattr(self, "visit_" + node.type): if self.debug: print "visiting:", node.type getattr(self, "visit_" + node.type)(node) elif node.children: for child in node.children: r.append(self.visit(child)) else: r += [self.get("value", u'')] r += [self.commentsPretty(node.commentsAfter)] return u''.join(r) def commentsPretty(self, comments): res = [] for i, commentNode in enumerate(comments): commentStr = self.visit(commentNode) res.append(commentStr) # handle additional line breaks between comments if i > 0: pass #curr_start = commentNode.get("line") #prev_start = comments[i-1].get("line") #prev_lines = res[i-1].count('\n') #addtl_lb = curr_start - prev_start + prev_lines #res[i-1] += addtl_lb * '\n' return u''.join(res) def infix(id_): def visit_(self, optns, state): r = self.commentsPretty(self.comments, optns, state) r += self.getChild(0).format(optns, state) r += ' ' r += self.get("value") r += ' ' r += self.getChild(1).format(optns, state) return r symbol(id_).format = format for sym in SYMBOLS['infix'] + SYMBOLS['infix_r']: infix(sym) ## # infix "verb" operators, i.e. that need a space around themselves (like 'instanceof', 'in') def infix_v(id_): def visit_(self, optns, state): # adapt the output r = self.commentsPretty(self.comments, optns, state) r += self.getChild(0).format(optns, state) r += self.space() r += self.get("value") r += self.space() r += self.getChild(1).format(optns, state) return r symbol(id_).format = format for sym in SYMBOLS['infix_v']: infix_v(sym) ## # prefix "sigil" operators, like '!', '~', ... def prefix(id_): def visit_(self, optns, state): r = self.commentsPretty(self.comments, optns, state) r += self.get("value") r += self.getChild(0).format(optns, state) return r symbol(id_).format = format for sym in SYMBOLS['prefix']: prefix(sym) ## # prefix "verb" operators, i.e. that need a space before their operand like 'delete' def prefix_v(id_): def visit_(self, optns, state): r = self.commentsPretty(self.comments, optns, state) r += self.get("value") r += self.space() r += self.getChild(0).format(optns, state) return r symbol(id_).format = format for sym in SYMBOLS['prefix_v']: prefix_v(sym) def preinfix(id_): # pre-/infix operators (+, -) def visit_(self, optns, state): # need to handle pre/infix cases r = self.commentsPretty(self.comments, optns, state) r = [r] first = self.getChild(0).format(optns, state) op = self.get("value") prefix = self.get("left", 0) if prefix and prefix == "true": r = [op, first] else: second = self.getChild(1).format(optns, state) r = [first, ' ', op, ' ', second] return ''.join(r) symbol(id_).format = format for sym in SYMBOLS['preinfix']: preinfix(sym) def prepostfix(id_): # pre-/post-fix operators (++, --) def visit_(self, optns, state): r = self.commentsPretty(self.comments, optns, state) operator = self.get("value") operand = self.getChild(0).format(optns, state) r += self.get("value") if self.get("left", '') == "true": r = [operator, operand] else: r = [operand, operator] return u''.join(r) symbol(id_).format = format for sym in SYMBOLS['prepostfix']: prepostfix(sym) def visit_constant(self, optns, state): r = self.commentsPretty(self.comments, optns, state) if self.get("constantType") == "string": if self.get("detail") == "singlequotes": r += self.write("'") else: r += self.write('"') r += self.write(self.get("value")) if self.get("detail") == "singlequotes": r += self.write("'") else: r += self.write('"') else: r += self.write(self.get("value")) return r def visit_identifier(self, optns, state): r = self.commentsPretty(self.comments, optns, state) v = self.get("value", u"") if v: r += self.write(v) return r def visit_hook(self, optns, state): r = self.commentsPretty(self.comments, optns, state) r = [r] r.append(self.getChild(0).format(optns, state)) r.append(' ') r.append('?') r.append(' ') r.append(self.getChild(1).format(optns, state)) r.append(' ') r.append(':') r.append(' ') r.append(self.getChild(2).format(optns, state)) return ''.join(r) def visit_dotaccessor(self, optns, state): r = self.commentsPretty(self.comments, optns, state) r += self.children[0].format(optns, state) r += '.' r += self.children[1].format(optns, state) return r def visit_operand(self, optns, state): r = self.commentsPretty(self.comments, optns, state) r += self.children[0].format(optns, state) return r def visit_group(self, optns, state): r = self.commentsPretty(self.comments, optns, state) r = [r] r.append('(') a = [] for c in self.children: a.append(c.format(optns, state)) r.append(', '.join(a)) r.append(')') return ''.join(r) def visit_accessor(self, optns, state): r = self.children[0].format(optns, state) r += self.commentsPretty(self.comments, optns, state) r += '[' r += self.children[1].format(optns, state) r += ']' return r def visit_array(self, optns, state): cmnts = self.commentsPretty(self.comments, optns, state) r = [] for c in self.children: r.append(c.format(optns, state)) return cmnts + '[' + u', '.join(r) + ']' def visit_key(self, optns, state): r = self.commentsPretty(self.comments, optns, state) r += self.children[0].format(optns, state) r += self.commentsPretty(self.commentsAfter, optns, state) return r def visit_map(self, optns, state): r = self.commentsPretty(self.comments, optns, state) r += self.write("{\n") state.indentLevel += 1 indent = indentString(optns, state) a = [] for c in self.children: a.append(indent + c.format(optns, state)) r += (',\n').join(a) state.indentLevel -= 1 if len(self.children): r += '\n' r += self.write("%s}" % indentString(optns, state)) return r def visit_value(self, optns, state): r = self.commentsPretty(self.comments, optns, state) r += self.children[0].format(optns, state) return r def visit_keyvalue(self, optns, state): r = self.commentsPretty(self.comments, optns, state) key = self.get("key") key_quote = self.get("quote", '') if key_quote: quote = '"' if key_quote == 'doublequotes' else "'" elif (key in lang.RESERVED or not identifier_regex.match(key) # TODO: or not lang.NUMBER_REGEXP.match(key) ): print "Warning: Auto protect key: %r" % key quote = '"' else: quote = '' value = self.getChild("value").format(optns, state) return r + quote + key + quote + ' : ' + value def visit_block(self, optns, state): r = self.commentsPretty(self.comments, optns, state) r = [r] r.append('{') r.append(self.children[0].format(optns, state)) r.append('}') return u''.join(r) def visit_function(self, optns, state): r = self.commentsPretty(self.comments, optns, state) r += self.write("function") if self.getChild("identifier", 0): functionName = self.getChild("identifier").get("value") r += self.space(result=r) r += self.write(functionName) # params r += self.getChild("params").format(optns, state) # body r += self.getChild("body").format(optns, state) return r def visit_body(self, optns, state): r = self.commentsPretty(self.comments, optns, state) r = [r] r.append(self.children[0].format(optns, state)) # 'if', 'while', etc. can have single-statement bodies if self.children[0].id != 'block': r.append(';') return u''.join(r) def visit_var(self, optns, state): r = self.commentsPretty(self.comments, optns, state) r = [r] r.append("var") r.append(self.space()) a = [] for c in self.children: a.append(c.format(optns, state)) r.append(','.join(a)) return ''.join(r) def visit_definition(self, optns, state): r = self.commentsPretty(self.comments, optns, state) r += self.children[0].format(optns, state) return r def visit_for(self, optns, state): r = self.commentsPretty(self.comments, optns, state) r = [r] r.append('for') r.append(self.space(False, result=r)) # cond r.append('(') # for (in) if self.get("forVariant") == "in": r.append(self.children[0].format(optns, state)) # for (;;) else: r.append(self.children[0].children[0].format(optns, state)) r.append(';') r.append(self.children[0].children[1].format(optns, state)) r.append(';') r.append(self.children[0].children[2].format(optns, state)) r.append(')') # body r.append(self.getChild("body").format(optns, state)) return u''.join(r) def visit_in(self, optns, state): r = self.commentsPretty(self.comments, optns, state) r += self.getChild(0).format(optns, state) r += self.space() r += 'in' r += self.space() r += self.getChild(1).format(optns, state) return r def visit_expressionList( self, optns, state ): # WARN: this conflicts (and is overwritten) in for(;;).format cmnts = self.commentsPretty(self.comments, optns, state) r = [] for c in self.children: r.append(c.format(optns, state)) return cmnts + ','.join(r) def visit_while(self, optns, state): r = self.commentsPretty(self.comments, optns, state) r += self.write("while") r += self.space(False, result=r) # cond r += '(' r += self.children[0].format(optns, state) r += ')' # body r += self.children[1].format(optns, state) return r def visit_with(self, optns, state): r = self.commentsPretty(self.comments, optns, state) r = [r] r.append("with") r.append(self.space()) r.append('(') r.append(self.children[0].format(optns, state)) r.append(')') r.append(self.children[1].format(optns, state)) return ''.join(r) def visit_do(self, optns, state): r = self.commentsPretty(self.comments, optns, state) r = [r] r.append("do") r.append(self.space()) r.append(self.children[0].format(optns, state)) r.append('while') r.append('(') r.append(self.children[1].format(optns, state)) r.append(')') return ''.join(r) def visit_if(self, optns, state): r = self.commentsPretty(self.comments, optns, state) # Additional new line before each loop if not self.isFirstChild(True) and not self.getChild( "commentsBefore", False): prev = self.getPreviousSibling(False, True) # No separation after case statements #if prev != None and prev.type in ["case", "default"]: # pass #elif self.hasChild("elseStatement") or self.getChild("statement").hasBlockChildren(): # self.sep() #else: # self.line() r += self.write("if") # condition r += self.write("(") r += self.children[0].format(optns, state) r += self.write(")") # 'then' part r += self.children[1].format(optns, state) # (opt) 'else' part if len(self.children) == 3: r += self.space() r += self.write("else") r += self.space() r += self.children[2].format(optns, state) r += self.space(False, result=r) return r def visit_loop(self, optns, state): r = self.commentsPretty(self.comments, optns, state) # Additional new line before each loop if not self.isFirstChild(True) and not self.getChild( "commentsBefore", False): prev = self.getPreviousSibling(False, True) # No separation after case statements if prev != None and prev.type in ["case", "default"]: pass elif self.hasChild("elseStatement") or self.getChild( "statement").hasBlockChildren(): self.sep() else: self.line() loopType = self.get("loopType") if loopType == "IF": pass # r += self.write("if") # r += self.space(False,result=r) # # condition # r += '(' # r += self.children[0].format(optns, state) # r += ')' # # then # r += self.children[1].format(optns, state) # # else # if len(self.children) == 3: # r += self.write("else") # r += self.children[2].format(optns, state) # r += self.space(False,result=r) elif loopType == "WHILE": r += self.write("while") r += self.space(False, result=r) elif loopType == "FOR": r += self.write("for") r += self.space(False, result=r) elif loopType == "DO": r += self.write("do") r += self.space(False, result=r) elif loopType == "WITH": r += self.write("with") r += self.space(False, result=r) else: print "Warning: Unknown loop type: %s" % loopType return r def visit_break(self, optns, state): r = self.commentsPretty(self.comments, optns, state) r += self.write("break") if self.children: r += self.space(result=r) r += self.write(self.children[0].format(optns, state)) return r def visit_continue(self, optns, state): r = self.commentsPretty(self.comments, optns, state) r += self.write("continue") if self.children: r += self.space(result=r) r += self.write(self.children[0].format(optns, state)) return r def visit_return(self, optns, state): r = [self.commentsPretty(self.comments, optns, state)] r += ["return"] if self.children: r.append(self.space()) r.append(self.children[0].format(optns, state)) return ''.join(r) def visit_switch(self, optns, state): r = self.commentsPretty(self.comments, optns, state) r = [r] r.append("switch") # control r.append('(') r.append(self.children[0].format(optns, state)) r.append(')') # body r.append('{') body = self.getChild("body") for c in body.children: r.append(c.format(optns, state)) r.append('}') return ''.join(r) def visit_case(self, optns, state): r = self.commentsPretty(self.comments, optns, state) r = [r] r.append('case') r.append(self.space()) r.append(self.children[0].format(optns, state)) r.append(':') if len(self.children) > 1: r.append(self.children[1].format(optns, state)) return ''.join(r) def visit_default(self, optns, state): r = self.commentsPretty(self.comments, optns, state) r = [r] r.append('default') r.append(':') if len(self.children) > 0: r.append(self.children[0].format(optns, state)) return ''.join(r) def visit_try(self, optns, state): r = self.commentsPretty(self.comments, optns, state) r = [r] r.append("try") r.append(self.children[0].format(optns, state)) catch = self.getChild("catch", 0) if catch: r.append(self.space()) r.append("catch") r.append(catch.children[0].format(optns, state)) r.append(self.space()) r.append(catch.children[1].format(optns, state)) finally_ = self.getChild("finally", 0) if finally_: r.append("finally") r.append(finally_.children[0].format(optns, state)) return ''.join(r) def visit_throw(self, optns, state): r = self.commentsPretty(self.comments, optns, state) r += 'throw' r += self.space() r += self.children[0].format(optns, state) return r def visit_empty(self, optns, state): r = self.commentsPretty(self.comments, optns, state) return r def visit_label(self, optns, state): r = self.commentsPretty(self.comments, optns, state) r = [r] r += [self.get("value")] # identifier r += [":"] r += [self.children[0].format(optns, state)] return ''.join(r) def visit_statements(self, optns, state): r = self.commentsPretty(self.comments, optns, state) r = [r] indent = indentString(optns, state) for cld in self.children: l = [indent] c = cld.format(optns, state) l.append(c) if not c or c[-1] != ';': l.append(';') r.append(u''.join(l)) return u'\n'.join(r) def visit_block(self, optns, state): r = self.commentsPretty(self.comments, optns, state) r += self.write("{\n") state.indentLevel += 1 a = [] for c in self.children: # should be just "statements" a.append(c.format(optns, state)) a_ = u''.join(a) r += a_ if a_: r += "\n" state.indentLevel -= 1 indent_string = indentString(optns, state) r += self.write(indent_string + "}") return r def visit_call(self, optns, state): r = self.commentsPretty(self.comments, optns, state) r += self.getChild("operand").format(optns, state) r += self.getChild("arguments").format(optns, state) return r def visit_comment(self, optns, state): r = self.get("value") r = Comment.Text(r).indent(indentString(optns, state)) if self.get( 'end', False) == True: # 'inline' needs terminating newline anyway r += '\n' r += indentString( optns, state ) # to pass on the indentation that was set ahead of the comment return r def visit_commentsAfter(self, optns, state): r = self.toJS(pp) return r def visit_commentsBefore(self, optns, state): r = self.toJS(pp) return r def visit_file(self, optns, state): r = self.commentsPretty(self.comments, optns, state) r += self.children[0].format(optns, state) return r def visit_first(self, optns, state): r = self.commentsPretty(self.comments, optns, state) if self.children: # could be empty in for(;;) r = self.children[0].format(optns, state) return r def visit_second(self, optns, state): r = self.commentsPretty(self.comments, optns, state) if self.children: r = self.children[0].format(optns, state) return r def visit_third(self, optns, state): r = self.commentsPretty(self.comments, optns, state) if self.children: r += self.children[0].format(optns, state) return r def visit_(self, optns, state): r = self.commentsPretty(self.comments, optns, state) self.noline() r += self.write("(") a = [] for c in self.children: a.append(c.format(optns, state)) r += u', '.join(a) r += self.write(")") return r symbol("params").format = format symbol("arguments").format = format