def transform_dictionary_comprehension(builder: IRBuilder, o: DictionaryComprehension) -> Value: d = builder.primitive_op(new_dict_op, [], o.line) loop_params = list(zip(o.indices, o.sequences, o.condlists)) def gen_inner_stmts() -> None: k = builder.accept(o.key) v = builder.accept(o.value) builder.primitive_op(dict_set_item_op, [d, k, v], o.line) comprehension_helper(builder, loop_params, gen_inner_stmts, o.line) return d
def transform_set_comprehension(builder: IRBuilder, o: SetComprehension) -> Value: gen = o.generator set_ops = builder.primitive_op(new_set_op, [], o.line) loop_params = list(zip(gen.indices, gen.sequences, gen.condlists)) def gen_inner_stmts() -> None: e = builder.accept(gen.left_expr) builder.primitive_op(set_add_op, [set_ops, e], o.line) comprehension_helper(builder, loop_params, gen_inner_stmts, o.line) return set_ops
def transform_dictionary_comprehension(builder: IRBuilder, o: DictionaryComprehension) -> Value: if any(o.is_async): builder.error('async comprehensions are unimplemented', o.line) d = builder.call_c(dict_new_op, [], o.line) loop_params = list(zip(o.indices, o.sequences, o.condlists)) def gen_inner_stmts() -> None: k = builder.accept(o.key) v = builder.accept(o.value) builder.call_c(dict_set_item_op, [d, k, v], o.line) comprehension_helper(builder, loop_params, gen_inner_stmts, o.line) return d
def translate_next_call(builder: IRBuilder, expr: CallExpr, callee: RefExpr) -> Optional[Value]: """Special case for calling next() on a generator expression, an idiom that shows up some in mypy. For example, next(x for x in l if x.id == 12, None) will generate code that searches l for an element where x.id == 12 and produce the first such object, or None if no such element exists. """ if not (expr.arg_kinds in ([ARG_POS], [ARG_POS, ARG_POS]) and isinstance(expr.args[0], GeneratorExpr)): return None gen = expr.args[0] retval = Register(builder.node_type(expr)) default_val = None if len(expr.args) > 1: default_val = builder.accept(expr.args[1]) exit_block = BasicBlock() def gen_inner_stmts() -> None: # next takes the first element of the generator, so if # something gets produced, we are done. builder.assign(retval, builder.accept(gen.left_expr), gen.left_expr.line) builder.goto(exit_block) loop_params = list(zip(gen.indices, gen.sequences, gen.condlists)) comprehension_helper(builder, loop_params, gen_inner_stmts, gen.line) # Now we need the case for when nothing got hit. If there was # a default value, we produce it, and otherwise we raise # StopIteration. if default_val: builder.assign(retval, default_val, gen.left_expr.line) builder.goto(exit_block) else: builder.add( RaiseStandardError(RaiseStandardError.STOP_ITERATION, None, expr.line)) builder.add(Unreachable()) builder.activate_block(exit_block) return retval
def any_all_helper(builder: IRBuilder, gen: GeneratorExpr, initial_value: Callable[[], Value], modify: Callable[[Value], Value], new_value: Callable[[], Value]) -> Value: retval = Register(bool_rprimitive) builder.assign(retval, initial_value(), -1) loop_params = list(zip(gen.indices, gen.sequences, gen.condlists)) true_block, false_block, exit_block = BasicBlock(), BasicBlock(), BasicBlock() def gen_inner_stmts() -> None: comparison = modify(builder.accept(gen.left_expr)) builder.add_bool_branch(comparison, true_block, false_block) builder.activate_block(true_block) builder.assign(retval, new_value(), -1) builder.goto(exit_block) builder.activate_block(false_block) comprehension_helper(builder, loop_params, gen_inner_stmts, gen.line) builder.goto_and_activate(exit_block) return retval
def translate_sum_call(builder: IRBuilder, expr: CallExpr, callee: RefExpr) -> Optional[Value]: # specialized implementation is used if: # - only one or two arguments given (if not, sum() has been given invalid arguments) # - first argument is a Generator (there is no benefit to optimizing the performance of eg. # sum([1, 2, 3]), so non-Generator Iterables are not handled) if not (len(expr.args) in (1, 2) and expr.arg_kinds[0] == ARG_POS and isinstance(expr.args[0], GeneratorExpr)): return None # handle 'start' argument, if given if len(expr.args) == 2: # ensure call to sum() was properly constructed if not expr.arg_kinds[1] in (ARG_POS, ARG_NAMED): return None start_expr = expr.args[1] else: start_expr = IntExpr(0) gen_expr = expr.args[0] target_type = builder.node_type(expr) retval = Register(target_type) builder.assign(retval, builder.coerce(builder.accept(start_expr), target_type, -1), -1) def gen_inner_stmts() -> None: call_expr = builder.accept(gen_expr.left_expr) builder.assign(retval, builder.binary_op(retval, call_expr, '+', -1), -1) loop_params = list( zip(gen_expr.indices, gen_expr.sequences, gen_expr.condlists)) comprehension_helper(builder, loop_params, gen_inner_stmts, gen_expr.line) return retval