Exemple #1
0
    def _constructInitialVarnameToType(self):
        input_types = self._input_types

        if self._ast_arg.vararg is not None:
            self._star_args_name = self._ast_arg.vararg.val.arg

        if self._star_args_name is None:
            if len(input_types) != len(self._ast_arg.args):
                raise ConversionException(
                    "Expected %s arguments but got %s" %
                    (len(self._ast_arg.args), len(input_types)))
        else:
            if len(input_types) < len(self._ast_arg.args):
                raise ConversionException(
                    "Expected at least %s arguments but got %s" %
                    (len(self._ast_arg.args), len(input_types)))

        self._native_args = []
        for i in range(len(self._ast_arg.args)):
            self._varname_to_type[self._ast_arg.args[i].arg] = input_types[i]
            if not input_types[i].is_empty:
                self._native_args.append(
                    (self._ast_arg.args[i].arg,
                     input_types[i].getNativePassingType()))

        self._argnames = [a.arg for a in self._ast_arg.args]

        if self._star_args_name is not None:
            star_args_count = len(input_types) - len(self._ast_arg.args)

            for i in range(len(self._ast_arg.args), len(input_types)):
                self._native_args.append(
                    ('.star_args.%s' % (i - len(self._ast_arg.args)),
                     input_types[i].getNativePassingType()))

            starargs_type = native_ast.Struct([
                ('f_%s' % i, input_types[i + len(self._ast_arg.args)])
                for i in range(star_args_count)
            ])

            self._varname_to_type[self._star_args_name] = starargs_type

        if self._output_type is not None:
            self._varname_to_type[FunctionOutput] = typeWrapper(
                self._output_type)

        self._functionOutputTypeKnown = FunctionOutput in self._varname_to_type
Exemple #2
0
    def named_var_expr(self, name):
        if self.functionContext._varname_to_type[name] is None:
            raise ConversionException("variable %s is not in scope here" %
                                      name)

        slot_type = self.functionContext._varname_to_type[name]

        return TypedExpression(self,
                               native_ast.Expression.StackSlot(
                                   name=name,
                                   type=slot_type.getNativeLayoutType()),
                               slot_type,
                               isReference=True)
Exemple #3
0
    def construct_stackslots_around(self, expr, argnames, stararg_name):
        to_add = []
        destructors = []

        for name in argnames:
            if name is not FunctionOutput and name != stararg_name:
                if name not in self._varname_to_type:
                    raise ConversionException(
                        "Couldn't find a type for argument %s" % name)
                slot_type = self._varname_to_type[name]

                if slot_type.is_empty:
                    # we don't need to generate a stackslot for this value. Whenever we look it up
                    # we'll simply make a void expression
                    pass
                elif slot_type is not None:
                    context = ExpressionConversionContext(self)

                    if slot_type.is_pod:
                        # we can just copy this into the stackslot directly. no destructor needed
                        context.pushEffect(
                            native_ast.Expression.Store(
                                ptr=native_ast.Expression.StackSlot(
                                    name=name,
                                    type=slot_type.getNativeLayoutType()),
                                val=(native_ast.Expression.Variable(
                                    name=name) if not slot_type.is_pass_by_ref
                                     else native_ast.Expression.Variable(
                                         name=name).load())))
                        context.pushEffect(
                            context.isInitializedVarExpr(name).expr.store(
                                native_ast.trueExpr))
                    else:
                        # need to make a stackslot for this variable
                        # the argument will be a pointer because it's POD
                        var_expr = context.inputArg(slot_type, name)

                        slot_expr = context.named_var_expr(name)

                        slot_type.convert_copy_initialize(
                            context, slot_expr, var_expr)

                        context.pushEffect(
                            context.isInitializedVarExpr(name).expr.store(
                                native_ast.trueExpr))

                    to_add.append(context.finalize(None))

        for name in self._varname_to_type:
            if name is not FunctionOutput and name != stararg_name:
                context = ExpressionConversionContext(self)

                if self._varname_to_type[name] is not None:
                    slot_expr = context.named_var_expr(name)

                    with context.ifelse(
                            context.isInitializedVarExpr(name)) as (true,
                                                                    false):
                        with true:
                            slot_expr.convert_destroy()

                    destructors.append(
                        native_ast.Teardown.Always(expr=context.finalize(
                            None).with_comment("Cleanup for variable %s" %
                                               name)))

                    if name not in argnames:
                        # this is a variable in the function that we assigned to. we need to ensure that
                        # the initializer flag is zero
                        context = ExpressionConversionContext(self)
                        context.pushEffect(
                            context.isInitializedVarExpr(name).expr.store(
                                native_ast.falseExpr))
                        to_add.append(context.finalize(None))

        if to_add:
            expr = native_ast.Expression.Sequence(vals=to_add + [expr])

        if destructors:
            expr = native_ast.Expression.Finally(teardowns=destructors,
                                                 expr=expr)

        return expr
Exemple #4
0
    def convert_statement_ast(self, ast):
        if ast.matches.Assign or ast.matches.AugAssign:
            if ast.matches.Assign:
                assert len(ast.targets) == 1
                op = None
                target = ast.targets[0]
            else:
                target = ast.target
                op = ast.op

            if target.matches.Name and target.ctx.matches.Store:
                varname = target.id

                if varname not in self._varname_to_type:
                    self._varname_to_type[varname] = None

                subcontext = ExpressionConversionContext(self)

                val_to_store = subcontext.convert_expression_ast(ast.value)

                if val_to_store is None:
                    return subcontext.finalize(None), False

                if op is not None:
                    if varname not in self._varname_to_type:
                        raise NotImplementedError()
                    else:
                        slot_ref = subcontext.named_var_expr(varname)
                        val_to_store = slot_ref.convert_bin_op(
                            op, val_to_store)

                        if val_to_store is None:
                            return subcontext.finalize(None), False

                self.generateAssignmentExpr(varname, val_to_store)

                return subcontext.finalize(None).with_comment("Assign %s" %
                                                              (varname)), True

            if target.matches.Subscript and target.ctx.matches.Store:
                assert target.slice.matches.Index

                subcontext = ExpressionConversionContext(self)

                slicing = subcontext.convert_expression_ast(target.value)
                if slicing is None:
                    return subcontext.finalize(None), False

                index = subcontext.convert_expression_ast(target.slice.value)

                if slicing is None:
                    return subcontext.finalize(None), False

                val_to_store = subcontext.convert_expression_ast(ast.value)

                if val_to_store is None:
                    return subcontext.finalize(None), False

                if op is not None:
                    val_to_store = slicing.convert_getitem(
                        index).convert_bin_op(op, val_to_store)
                    if val_to_store is None:
                        return subcontext.finalize(None), False

                slicing.convert_setitem(index, val_to_store)

                return subcontext.finalize(None), True

            if target.matches.Attribute and target.ctx.matches.Store:
                subcontext = ExpressionConversionContext(self)

                slicing = subcontext.convert_expression_ast(target.value)
                attr = target.attr

                val_to_store = subcontext.convert_expression_ast(ast.value)
                if val_to_store is None:
                    return subcontext.finalize(None), False

                if op is not None:
                    input_val = slicing.convert_attribute(attr)
                    if input_val is None:
                        return subcontext.finalize(None), False

                    val_to_store = input_val.convert_bin_op(op, val_to_store)
                    if val_to_store is None:
                        return subcontext.finalize(None), False

                slicing.convert_set_attribute(attr, val_to_store)

                return subcontext.finalize(None), True

        if ast.matches.Return:
            subcontext = ExpressionConversionContext(self)

            if ast.value is None:
                e = subcontext.convert_expression_ast(
                    python_ast.Expr.Num(n=python_ast.NumericConstant.None_()))
            else:
                e = subcontext.convert_expression_ast(ast.value)

            if e is None:
                return subcontext.finalize(None), False

            if not self._functionOutputTypeKnown:
                if self._varname_to_type.get(FunctionOutput) is None:
                    self.markTypesAreUnstable()
                    self._varname_to_type[FunctionOutput] = e.expr_type
                else:
                    self.upsizeVariableType(FunctionOutput, e.expr_type)

            if e.expr_type != self._varname_to_type[FunctionOutput]:
                e = e.convert_to_type(self._varname_to_type[FunctionOutput])

            if e is None:
                return subcontext.finalize(None), False

            if e.expr_type.is_pass_by_ref:
                returnTarget = TypedExpression(
                    subcontext, native_ast.Expression.Variable(name=".return"),
                    self._varname_to_type[FunctionOutput], True)

                returnTarget.convert_copy_initialize(e)

                subcontext.pushTerminal(native_ast.Expression.Return(arg=None))
            else:
                subcontext.pushTerminal(
                    native_ast.Expression.Return(arg=e.nonref_expr))

            return subcontext.finalize(None), False

        if ast.matches.Expr:
            subcontext = ExpressionConversionContext(self)

            result_expr = subcontext.convert_expression_ast(ast.value)

            return subcontext.finalize(result_expr), result_expr is not None

        if ast.matches.If:
            cond_context = ExpressionConversionContext(self)
            cond = cond_context.convert_expression_ast(ast.test)
            if cond is None:
                return cond_context.finalize(None), False
            cond = cond.toBool()
            if cond is None:
                return cond_context.finalize(None), False

            if cond.expr.matches.Constant:
                truth_val = cond.expr.val.truth_value()

                branch, flow_returns = self.convert_statement_list_ast(
                    ast.body if truth_val else ast.orelse)

                return cond.expr + branch, flow_returns

            true, true_returns = self.convert_statement_list_ast(ast.body)
            false, false_returns = self.convert_statement_list_ast(ast.orelse)

            return (native_ast.Expression.Branch(
                cond=cond_context.finalize(cond.nonref_expr),
                true=true,
                false=false), true_returns or false_returns)

        if ast.matches.Pass:
            return native_ast.nullExpr, True

        if ast.matches.While:
            cond_context = ExpressionConversionContext(self)

            cond = cond_context.convert_expression_ast(ast.test)

            if cond is None:
                return cond_context.finalize(None), False
            cond = cond.toBool()
            if cond is None:
                return cond_context.finalize(None), False

            true, true_returns = self.convert_statement_list_ast(ast.body)

            false, false_returns = self.convert_statement_list_ast(ast.orelse)

            return (native_ast.Expression.While(
                cond=cond_context.finalize(cond.nonref_expr),
                while_true=true,
                orelse=false), true_returns or false_returns)

        if ast.matches.Try:
            raise NotImplementedError()

        if ast.matches.For:
            if not ast.target.matches.Name:
                raise NotImplementedError(
                    "Can't handle multi-variable loop expressions")

            target_var_name = ast.target.id

            # create a variable to hold the iterator, and instantiate it there
            iter_varname = target_var_name + ".iter." + str(ast.line_number)

            iterator_setup_context = ExpressionConversionContext(self)
            to_iterate = iterator_setup_context.convert_expression_ast(
                ast.iter)
            if to_iterate is None:
                return iterator_setup_context.finalize(to_iterate), False
            iterator_object = to_iterate.convert_method_call(
                "__iter__", (), {})
            if iterator_object is None:
                return iterator_setup_context.finalize(iterator_object), False
            self.generateAssignmentExpr(iter_varname, iterator_object)

            cond_context = ExpressionConversionContext(self)
            iter_obj = cond_context.named_var_expr(iter_varname)
            next_ptr, is_populated = iter_obj.convert_next(
            )  # this conversion is special - it returns two values

            with cond_context.ifelse(is_populated.nonref_expr) as (if_true,
                                                                   if_false):
                with if_true:
                    self.generateAssignmentExpr(target_var_name, next_ptr)

            true, true_returns = self.convert_statement_list_ast(ast.body)

            false, false_returns = self.convert_statement_list_ast(ast.orelse)

            return (iterator_setup_context.finalize(None) >>
                    native_ast.Expression.While(
                        cond=cond_context.finalize(is_populated),
                        while_true=true,
                        orelse=false), true_returns or false_returns)

        if ast.matches.Raise:
            raise NotImplementedError()

        raise ConversionException("Can't handle python ast Statement.%s" %
                                  ast._which)
Exemple #5
0
    def convert_expression_ast(self, ast):
        if ast.matches.Attribute:
            attr = ast.attr
            val = self.convert_expression_ast(ast.value)

            return val.convert_attribute(attr)

        if ast.matches.Name:
            assert ast.ctx.matches.Load
            if ast.id in self.functionContext._varname_to_type:
                with self.ifelse(self.isInitializedVarExpr(ast.id)) as (true,false):
                    with false:
                        self.pushException(UnboundLocalError, "local variable '%s' referenced before assignment" % ast.id)
                return self.named_var_expr(ast.id)

            if ast.id in self.functionContext._free_variable_lookup:
                return pythonObjectRepresentation(self, self.functionContext._free_variable_lookup[ast.id])

            elif ast.id in __builtins__:
                return pythonObjectRepresentation(self, __builtins__[ast.id])

            if ast.id not in self.functionContext._varname_to_type:
                self.pushException(NameError, "name '%s' is not defined" % ast.id)
                return None

        if ast.matches.Num:
            if ast.n.matches.None_:
                return pythonObjectRepresentation(self, None)
            if ast.n.matches.Boolean:
                return pythonObjectRepresentation(self, bool(ast.n.value))
            if ast.n.matches.Int:
                return pythonObjectRepresentation(self, int(ast.n.value))
            if ast.n.matches.Float:
                return pythonObjectRepresentation(self, float(ast.n.value))

        if ast.matches.Str:
            return pythonObjectRepresentation(self, ast.s)

        if ast.matches.BoolOp:
            values = []
            for v in ast.values:
                v = self.convert_expression_ast(v)
                if v is not None:
                    v = v.toBool()
                values.append(v)

            op = ast.op

            expr_so_far = []

            for v in ast.values:
                v = self.convert_expression_ast(v)
                if v is None:
                    expr_so_far.append(None)
                    break
                v = v.toBool()
                if v is None:
                    expr_so_far.append(None)
                    break

                expr_so_far.append(v.expr)

                if expr_so_far[-1] is None:
                    if len(expr_so_far) == 1:
                        return None
                elif expr_so_far[-1].matches.Constant:
                    if (expr_so_far[-1].val.val and op.matches.Or or
                                (not expr_so_far[-1].val.val) and op.matches.And):
                        #this is a short-circuit
                        if len(expr_so_far) == 1:
                            return expr_so_far[0]

                        return TypedExpression(
                            self,
                            native_ast.Expression.Sequence(expr_so_far),
                            typeWrapper(bool),
                            False
                            )
                    else:
                        expr_so_far.pop()

            if not expr_so_far:
                if op.matches.Or:
                    #must have had all False constants
                    return TypedExpression(self, native_ast.falseExpr, typeWrapper(bool), False)
                else:
                    #must have had all True constants
                    return TypedExpression(self, native_ast.trueExpr, typeWrapper(bool), False)

            while len(expr_so_far) > 1:
                l,r = expr_so_far[-2], expr_so_far[-1]
                expr_so_far.pop()
                expr_so_far.pop()

                if op.matches.And:
                    new_expr = native_ast.Expression.Branch(cond=l, true=r, false=native_ast.falseExpr)
                else:
                    new_expr = native_ast.Expression.Branch(cond=l, true=native_ast.trueExpr, false=r)

                expr_so_far.append(new_expr)

            return TypedExpression(self, expr_so_far[0], typeWrapper(bool), False)

        if ast.matches.BinOp:
            l = self.convert_expression_ast(ast.left)

            if l is None:
                return None

            r = self.convert_expression_ast(ast.right)

            if r is None:
                return None

            return l.convert_bin_op(ast.op, r)

        if ast.matches.UnaryOp:
            operand = self.convert_expression_ast(ast.operand)

            return operand.convert_unary_op(ast.op)

        if ast.matches.Subscript:
            assert ast.slice.matches.Index

            val = self.convert_expression_ast(ast.value)
            if val is None:
                return None
            index = self.convert_expression_ast(ast.slice.value)
            if index is None:
                return None

            return val.convert_getitem(index)

        if ast.matches.Call:
            l = self.convert_expression_ast(ast.func)

            if l is None:
                return None

            ast_args = ast.args
            stararg = None

            for a in ast_args:
                assert not a.matches.Starred, "not implemented yet"

            args = []
            for a in ast_args:
                args.append(self.convert_expression_ast(a))
                if args[-1] is None:
                    return None

            return l.convert_call(args)

        if ast.matches.Compare:
            assert len(ast.comparators) == 1, "multi-comparison not implemented yet"
            assert len(ast.ops) == 1

            l = self.convert_expression_ast(ast.left)
            r = self.convert_expression_ast(ast.comparators[0])

            return l.convert_bin_op(ast.ops[0], r)

        if ast.matches.Tuple:
            raise NotImplementedError("not implemented yet")

        if ast.matches.IfExp:
            test = self.convert_expression_ast(ast.test)
            if test is None:
                return None
            test = test.toBool()
            if test is None:
                return None

            with self.ifelse(test) as (true_block, false_block):
                with true_block:
                    true_res = self.convert_expression_ast(ast.body)
                with false_block:
                    false_res = self.conversion_exception(ast.orelse)

                if true_res.expr_type != false_res.expr_type:
                    out_type = typeWrapper(OneOf(true_res.expr_type.typeRepresentation, false_res.expr_type.typeRepresentation))
                else:
                    out_type = true_res.expr_type

                out_slot = self.allocateUninitializedSlot(out_type)

                with true_block:
                    true_res = true_res.convert_to_type(out_type)
                    out_slot.convert_copy_initialize(true_res)
                    self.markUninitializedSlotInitialized(out_slot)

                with false_block:
                    false_res = false_res.convert_to_type(out_type)
                    out_slot.convert_copy_initialize(false_res)
                    self.markUninitializedSlotInitialized(out_slot)

            return out_slot

        raise ConversionException("can't handle python expression type %s" % ast._which)
Exemple #6
0
    def convert_statement_ast(self, ast):
        if ast.matches.Assign or ast.matches.AugAssign:
            if ast.matches.Assign:
                assert len(ast.targets) == 1
                op = None
                target = ast.targets[0]
            else:
                target = ast.target
                op = ast.op

            if target.matches.Name and target.ctx.matches.Store:
                varname = target.id

                if varname not in self._varname_to_type:
                    self._varname_to_type[varname] = None

                subcontext = ExpressionConversionContext(self)

                val_to_store = subcontext.convert_expression_ast(ast.value)

                if val_to_store is None:
                    return subcontext.finalize(None), False

                if op is not None:
                    if varname not in self._varname_to_type:
                        raise NotImplementedError()
                    else:
                        slot_ref = subcontext.named_var_expr(varname)
                        val_to_store = slot_ref.convert_bin_op(
                            op, val_to_store)

                        if val_to_store is None:
                            return subcontext.finalize(None), False

                self.upsizeVariableType(varname, val_to_store.expr_type)
                slot_ref = subcontext.named_var_expr(varname)

                #convert the value to the target type now that we've upsized it
                val_to_store = val_to_store.convert_to_type(slot_ref.expr_type)

                assert val_to_store is not None, "We should always be able to upsize"

                if slot_ref.expr_type.is_pod:
                    slot_ref.convert_copy_initialize(val_to_store)
                    subcontext.pushEffect(
                        subcontext.isInitializedVarExpr(varname).expr.store(
                            native_ast.trueExpr))
                else:
                    with subcontext.ifelse(
                            subcontext.isInitializedVarExpr(varname)) as (
                                true_block, false_block):
                        with true_block:
                            slot_ref.convert_assign(val_to_store)
                        with false_block:
                            slot_ref.convert_copy_initialize(val_to_store)
                            subcontext.pushEffect(
                                subcontext.isInitializedVarExpr(
                                    varname).expr.store(native_ast.trueExpr))

                return subcontext.finalize(None).with_comment("Assign %s" %
                                                              (varname)), True

            if target.matches.Subscript and target.ctx.matches.Store:
                assert target.slice.matches.Index

                subcontext = ExpressionConversionContext(self)

                slicing = subcontext.convert_expression_ast(target.value)
                if slicing is None:
                    return subcontext.finalize(None), False

                index = subcontext.convert_expression_ast(target.slice.value)

                if slicing is None:
                    return subcontext.finalize(None), False

                val_to_store = subcontext.convert_expression_ast(ast.value)

                if val_to_store is None:
                    return subcontext.finalize(None), False

                if op is not None:
                    val_to_store = slicing.convert_getitem(
                        index).convert_bin_op(op, val_to_store)
                    if val_to_store is None:
                        return subcontext.finalize(None), False

                slicing.convert_setitem(index, val_to_store)

                return subcontext.finalize(None), True

            if target.matches.Attribute and target.ctx.matches.Store:
                subcontext = ExpressionConversionContext(self)

                slicing = subcontext.convert_expression_ast(target.value)
                attr = target.attr

                val_to_store = subcontext.convert_expression_ast(ast.value)
                if val_to_store is None:
                    return subcontext.finalize(None), False

                if op is not None:
                    input_val = slicing.convert_attribute(attr)
                    if input_val is None:
                        return subcontext.finalize(None), False

                    val_to_store = input_val.convert_bin_op(op, val_to_store)
                    if val_to_store is None:
                        return subcontext.finalize(None), False

                slicing.convert_set_attribute(attr, val_to_store)

                return subcontext.finalize(None), True

        if ast.matches.Return:
            subcontext = ExpressionConversionContext(self)

            if ast.value is None:
                e = subcontext.convert_expression_ast(
                    python_ast.Expr.Num(n=python_ast.NumericConstant.None_()))
            else:
                e = subcontext.convert_expression_ast(ast.value)

            if e is None:
                return subcontext.finalize(None), False

            if not self._functionOutputTypeKnown:
                if self._varname_to_type.get(FunctionOutput) is None:
                    self._typesAreUnstable = True
                    self._varname_to_type[FunctionOutput] = e.expr_type
                else:
                    self.upsizeVariableType(FunctionOutput, e.expr_type)

            if e.expr_type != self._varname_to_type[FunctionOutput]:
                e = e.convert_to_type(self._varname_to_type[FunctionOutput])

            if e is None:
                return subcontext.finalize(None), False

            if e.expr_type.is_pass_by_ref:
                returnTarget = TypedExpression(
                    subcontext, native_ast.Expression.Variable(name=".return"),
                    self._varname_to_type[FunctionOutput], True)

                returnTarget.convert_copy_initialize(e)

                subcontext.pushTerminal(native_ast.Expression.Return(arg=None))
            else:
                subcontext.pushTerminal(
                    native_ast.Expression.Return(arg=e.nonref_expr))

            return subcontext.finalize(None), False

        if ast.matches.Expr:
            subcontext = ExpressionConversionContext(self)

            result_expr = subcontext.convert_expression_ast(ast.value)

            return subcontext.finalize(result_expr), result_expr is not None

        if ast.matches.If:
            cond_context = ExpressionConversionContext(self)
            cond = cond_context.convert_expression_ast(ast.test)
            if cond is None:
                return cond.finalize(None), False
            cond = cond.toBool()
            if cond is None:
                return cond.finalize(None), False

            if cond.expr.matches.Constant:
                truth_val = cond.expr.val.truth_value()

                branch, flow_returns = self.convert_statement_list_ast(
                    ast.body if truth_val else ast.orelse)

                return cond.expr + branch, flow_returns

            true, true_returns = self.convert_statement_list_ast(ast.body)
            false, false_returns = self.convert_statement_list_ast(ast.orelse)

            return (native_ast.Expression.Branch(
                cond=cond_context.finalize(cond.nonref_expr),
                true=true,
                false=false), true_returns or false_returns)

        if ast.matches.Pass:
            return native_ast.nullExpr, True

        if ast.matches.While:
            cond_context = ExpressionConversionContext(self)

            cond = cond_context.convert_expression_ast(ast.test)

            if cond is None:
                return cond_context.finalize(None), False
            cond = cond.toBool()
            if cond is None:
                return cond_context.finalize(None), False

            true, true_returns = self.convert_statement_list_ast(ast.body)

            false, false_returns = self.convert_statement_list_ast(ast.orelse)

            return (native_ast.Expression.While(
                cond=cond_context.finalize(cond.nonref_expr),
                while_true=true,
                orelse=false), true_returns or false_returns)

        if ast.matches.Try:
            raise NotImplementedError()

        if ast.matches.For:
            raise NotImplementedError()

        if ast.matches.Raise:
            raise NotImplementedError()

        raise ConversionException("Can't handle python ast Statement.%s" %
                                  ast._which)
Exemple #7
0
    def convert_expression_ast(self, ast):
        if ast.matches.Attribute:
            attr = ast.attr
            val = self.convert_expression_ast(ast.value)

            if val is None:
                return None

            return val.convert_attribute(attr)

        if ast.matches.Name:
            assert ast.ctx.matches.Load
            if ast.id in self.functionContext._varname_to_type:
                with self.ifelse(self.isInitializedVarExpr(ast.id)) as (true,
                                                                        false):
                    with false:
                        self.pushException(
                            UnboundLocalError,
                            "local variable '%s' referenced before assignment"
                            % ast.id)
                return self.named_var_expr(ast.id)

            if ast.id in self.functionContext._free_variable_lookup:
                return pythonObjectRepresentation(
                    self, self.functionContext._free_variable_lookup[ast.id])

            elif ast.id in __builtins__:
                return pythonObjectRepresentation(self, __builtins__[ast.id])

            if ast.id not in self.functionContext._varname_to_type:
                self.pushException(NameError,
                                   "name '%s' is not defined" % ast.id)
                return None

        if ast.matches.Num:
            if ast.n.matches.None_:
                return pythonObjectRepresentation(self, None)
            if ast.n.matches.Boolean:
                return pythonObjectRepresentation(self, bool(ast.n.value))
            if ast.n.matches.Int:
                return pythonObjectRepresentation(self, int(ast.n.value))
            if ast.n.matches.Float:
                return pythonObjectRepresentation(self, float(ast.n.value))

        if ast.matches.Str:
            return pythonObjectRepresentation(self, ast.s)

        if ast.matches.BoolOp:

            def convertBoolOp(depth=0):
                with self.subcontext() as sc:
                    value = self.convert_expression_ast(ast.values[depth])
                    value = TypedExpression.asBool(value)
                    if value is not None:
                        if depth == len(ast.values) - 1:
                            sc.expr = value.expr
                        else:
                            tail_expr = convertBoolOp(depth + 1)

                            if ast.op.matches.And:
                                sc.expr = native_ast.Expression.Branch(
                                    cond=value.expr,
                                    true=tail_expr,
                                    false=native_ast.falseExpr)
                            elif ast.op.matches.Or:
                                sc.expr = native_ast.Expression.Branch(
                                    cond=value.expr,
                                    true=native_ast.trueExpr,
                                    false=tail_expr)
                            else:
                                raise Exception(
                                    f"Unknown kind of Boolean operator: {ast.op.Name}"
                                )

                return sc.result

            return TypedExpression(self, convertBoolOp(), typeWrapper(bool),
                                   False)

        if ast.matches.BinOp:
            lhs = self.convert_expression_ast(ast.left)

            if lhs is None:
                return None

            rhs = self.convert_expression_ast(ast.right)

            if rhs is None:
                return None

            return lhs.convert_bin_op(ast.op, rhs)

        if ast.matches.UnaryOp:
            operand = self.convert_expression_ast(ast.operand)

            return operand.convert_unary_op(ast.op)

        if ast.matches.Subscript:
            assert ast.slice.matches.Index

            val = self.convert_expression_ast(ast.value)
            if val is None:
                return None
            index = self.convert_expression_ast(ast.slice.value)
            if index is None:
                return None

            return val.convert_getitem(index)

        if ast.matches.Call:
            lhs = self.convert_expression_ast(ast.func)

            if lhs is None:
                return None

            for a in ast.args:
                assert not a.matches.Starred, "not implemented yet"

            args = []
            kwargs = {}

            for a in ast.args:
                args.append(self.convert_expression_ast(a))
                if args[-1] is None:
                    return None

            for keywordArg in ast.keywords:
                argname = keywordArg.arg

                kwargs[argname] = self.convert_expression_ast(keywordArg.value)
                if kwargs[argname] is None:
                    return None

            return lhs.convert_call(args, kwargs)

        if ast.matches.Compare:
            assert len(
                ast.comparators) == 1, "multi-comparison not implemented yet"
            assert len(ast.ops) == 1

            lhs = self.convert_expression_ast(ast.left)

            if lhs is None:
                return None

            r = self.convert_expression_ast(ast.comparators[0])

            if r is None:
                return None

            return lhs.convert_bin_op(ast.ops[0], r)

        if ast.matches.Tuple:
            raise NotImplementedError("not implemented yet")

        if ast.matches.IfExp:
            test = self.convert_expression_ast(ast.test)
            if test is None:
                return None
            test = test.toBool()
            if test is None:
                return None

            with self.ifelse(test) as (true_block, false_block):
                with true_block:
                    true_res = self.convert_expression_ast(ast.body)
                with false_block:
                    false_res = self.conversion_exception(ast.orelse)

                if true_res.expr_type != false_res.expr_type:
                    out_type = typeWrapper(
                        OneOf(true_res.expr_type.typeRepresentation,
                              false_res.expr_type.typeRepresentation))
                else:
                    out_type = true_res.expr_type

                out_slot = self.allocateUninitializedSlot(out_type)

                with true_block:
                    true_res = true_res.convert_to_type(out_type)
                    out_slot.convert_copy_initialize(true_res)
                    self.markUninitializedSlotInitialized(out_slot)

                with false_block:
                    false_res = false_res.convert_to_type(out_type)
                    out_slot.convert_copy_initialize(false_res)
                    self.markUninitializedSlotInitialized(out_slot)

            return out_slot

        raise ConversionException("can't handle python expression type %s" %
                                  ast._which)