def visit_comparison_expr(self, expr: ComparisonExpr) -> Expression: results = [] for index in range(len(expr.operators)): left, right = expr.operands[index], expr.operands[index + 1] operator = expr.operators[index] opExpr = OpExpr(operator, left, right) result = opExpr.accept(self) results.append(result) # Do the and of all comparisons for r in results: if not isinstance(r, IntExpr): raise Exception if r.value == 0: return IntExpr(0) return IntExpr(1)
def visit_BinOp(self, n: ast27.BinOp) -> OpExpr: op = self.from_operator(n.op) if op is None: raise RuntimeError('cannot translate BinOp ' + str(type(n.op))) return OpExpr(op, self.visit(n.left), self.visit(n.right))
def visit_JoinedStr(self, n: ast3.JoinedStr) -> Expression: result_expression = StrExpr('') # type: Expression for value_expr in self.translate_expr_list(n.values): string_method = MemberExpr(value_expr, '__str__') string_method.set_line(value_expr) stringified_value_expr = CallExpr(string_method, [], []) stringified_value_expr.set_line(value_expr) result_expression = OpExpr('+', result_expression, stringified_value_expr) result_expression.set_line(value_expr) return result_expression
def visit_op_expr(self, e: OpExpr) -> None: super().visit_op_expr(e) if e.op in ['and', 'or']: target = self.get_type(e) e.left = self.coerce(e.left, target, self.get_type(e.left), self.type_context()) e.right = self.coerce(e.right, target, self.get_type(e.right), self.type_context()) else: method_type = e.method_type if self.dynamic_funcs[-1] or isinstance(method_type, AnyType): e.left = self.coerce_to_dynamic(e.left, self.get_type(e.left), self.type_context()) e.right = self.coerce(e.right, AnyType(), self.get_type(e.right), self.type_context()) elif method_type: method_callable = cast(Callable, method_type) operand = e.right # For 'in', the order of operands is reversed. if e.op == 'in': operand = e.left # TODO arg_types[0] may not be reliable operand = self.coerce(operand, method_callable.arg_types[0], self.get_type(operand), self.type_context()) if e.op == 'in': e.left = operand else: e.right = operand
def visit_op_expr(self, e: OpExpr) -> None: super().visit_op_expr(e) if e.op in ["and", "or"]: target = self.get_type(e) e.left = self.coerce(e.left, target, self.get_type(e.left), self.type_context()) e.right = self.coerce(e.right, target, self.get_type(e.right), self.type_context()) else: method_type = e.method_type if self.dynamic_funcs[-1] or isinstance(method_type, AnyType): e.left = self.coerce_to_dynamic(e.left, self.get_type(e.left), self.type_context()) e.right = self.coerce(e.right, AnyType(), self.get_type(e.right), self.type_context()) elif method_type: method_callable = cast(Callable, method_type) operand = e.right # For 'in', the order of operands is reversed. if e.op == "in": operand = e.left # TODO arg_types[0] may not be reliable operand = self.coerce( operand, method_callable.arg_types[0], self.get_type(operand), self.type_context() ) if e.op == "in": e.left = operand else: e.right = operand
def visit_op_expr(self, e: OpExpr) -> None: super().visit_op_expr(e) if e.op in ['and', 'or']: target = self.get_type(e) e.left = self.coerce(e.left, target, self.get_type(e.left), self.type_context()) e.right = self.coerce(e.right, target, self.get_type(e.right), self.type_context()) else: method_type = e.method_type if self.dynamic_funcs[-1] or isinstance(method_type, AnyType): e.left = self.coerce_to_dynamic(e.left, self.get_type(e.left), self.type_context()) e.right = self.coerce(e.right, AnyType(), self.get_type(e.right), self.type_context()) elif method_type: method_callable = cast(Callable, method_type) operand = e.right # TODO arg_types[0] may not be reliable operand = self.coerce(operand, method_callable.arg_types[0], self.get_type(operand), self.type_context()) e.right = operand
def group(vals): if len(vals) == 2: return OpExpr(op, vals[0], vals[1]) else: return OpExpr(op, vals[0], group(vals[1:]))
def group(self, vals: List[Expression], op: str) -> OpExpr: if len(vals) == 2: return OpExpr(op, vals[0], vals[1]) else: return OpExpr(op, vals[0], self.group(vals[1:], op))
def group(vals: List[Expression]) -> OpExpr: if len(vals) == 2: return OpExpr(op, vals[0], vals[1]) else: return OpExpr(op, vals[0], group(vals[1:]))
def visit_op_expr(self, node: OpExpr) -> Node: new = OpExpr(node.op, self.node(node.left), self.node(node.right)) new.method_type = self.optional_type(node.method_type) return new
def transform_comparison_expr(builder: IRBuilder, e: ComparisonExpr) -> Value: # x in (...)/[...] # x not in (...)/[...] first_op = e.operators[0] if (first_op in ['in', 'not in'] and len(e.operators) == 1 and isinstance(e.operands[1], (TupleExpr, ListExpr))): items = e.operands[1].items n_items = len(items) # x in y -> x == y[0] or ... or x == y[n] # x not in y -> x != y[0] and ... and x != y[n] # 16 is arbitrarily chosen to limit code size if 1 < n_items < 16: if e.operators[0] == 'in': bin_op = 'or' cmp_op = '==' else: bin_op = 'and' cmp_op = '!=' lhs = e.operands[0] mypy_file = builder.graph['builtins'].tree assert mypy_file is not None bool_type = Instance(cast(TypeInfo, mypy_file.names['bool'].node), []) exprs = [] for item in items: expr = ComparisonExpr([cmp_op], [lhs, item]) builder.types[expr] = bool_type exprs.append(expr) or_expr: Expression = exprs.pop(0) for expr in exprs: or_expr = OpExpr(bin_op, or_expr, expr) builder.types[or_expr] = bool_type return builder.accept(or_expr) # x in [y]/(y) -> x == y # x not in [y]/(y) -> x != y elif n_items == 1: if e.operators[0] == 'in': cmp_op = '==' else: cmp_op = '!=' e.operators = [cmp_op] e.operands[1] = items[0] # x in []/() -> False # x not in []/() -> True elif n_items == 0: if e.operators[0] == 'in': return builder.false() else: return builder.true() if first_op in ('is', 'is not') and len(e.operators) == 1: right = e.operands[1] if isinstance(right, NameExpr) and right.fullname == 'builtins.None': # Special case 'is None' / 'is not None'. return translate_is_none(builder, e.operands[0], negated=first_op != 'is') # TODO: Don't produce an expression when used in conditional context # All of the trickiness here is due to support for chained conditionals # (`e1 < e2 > e3`, etc). `e1 < e2 > e3` is approximately equivalent to # `e1 < e2 and e2 > e3` except that `e2` is only evaluated once. expr_type = builder.node_type(e) # go(i, prev) generates code for `ei opi e{i+1} op{i+1} ... en`, # assuming that prev contains the value of `ei`. def go(i: int, prev: Value) -> Value: if i == len(e.operators) - 1: return transform_basic_comparison( builder, e.operators[i], prev, builder.accept(e.operands[i + 1]), e.line) next = builder.accept(e.operands[i + 1]) return builder.builder.shortcircuit_helper( 'and', expr_type, lambda: transform_basic_comparison( builder, e.operators[i], prev, next, e.line), lambda: go(i + 1, next), e.line) return go(0, builder.accept(e.operands[0]))
def group(vals: List[Node]) -> Node: if len(vals) == 2: return OpExpr(op, vals[0], vals[1]) else: return OpExpr(op, vals[0], group(vals[1:]))
def group(self, op: str, vals: List[Expression], n: ast3.expr) -> OpExpr: if len(vals) == 2: e = OpExpr(op, vals[0], vals[1]) else: e = OpExpr(op, vals[0], self.group(op, vals[1:], n)) return self.set_line(e, n)