예제 #1
0
    def visit_printf(self, node, args):
        '''
        printf function call
        '''

        # Extract format and args
        if len(args) == 0:
            self.addwarn("'printf' with zero args at line %s" % (
                node.coord.line,))
            fmt = Const('?', line=node.coord.line)
        else:
            if isinstance(args[0], Const):
                fmt = args[0]
                args = args[1:]
            else:
                self.addwarn("First argument of 'printf' at lines %s should \
be a format" % (node.coord.line,))
                fmt = Const('?', line=node.coord.line)

        fmt.value = fmt.value.replace('%lf', '%f')
        fmt.value = fmt.value.replace('%ld', '%d')
        fmt.value = fmt.value.replace('%lld', '%d')

        expr = Op('StrAppend', Var(VAR_OUT),
                  Op('StrFormat', fmt, *args, line=node.coord.line),
                  line=node.coord.line)
        self.addexpr(VAR_OUT, expr)
예제 #2
0
    def visit_AugAssign(self, node):

        # Aug assign to a name
        if isinstance(node.target, ast.Name):
            target = Var(node.target.id)
            self.addtype(node.target.id, '*')
            value = self.visit_expr(node.value)
            rhs = Op(node.op.__class__.__name__,
                     target,
                     value,
                     line=node.lineno)
            self.addexpr(target.name, rhs)

        # Aug assign to a index
        elif isinstance(node.target, ast.Subscript):
            if isinstance(node.target.slice, ast.Index):
                var = Var(node.target.value.id)
                right = self.visit_expr(node.value)
                index = self.visit_expr(node.target.slice.value)
                rhs = Op(node.op.__class__.__name__,
                         self.visit(node.target),
                         right,
                         line=node.lineno)
                self.addexpr(
                    var.name,
                    Op('AssignElement', var, index, rhs, line=node.lineno))

            else:
                raise NotSupported(
                    'Subscript assignments only allowed to Indices',
                    line=node.lineno)
        else:
            raise NotSupported('Assignments to {} not supported'.format(
                node.target.__class__.__name__),
                               line=node.lineno)
예제 #3
0
    def visit_FuncCall(self, node):
        '''
        FuncCall
        Attrs: name, args
        '''

        # Get (and check) name
        name = self.visit_expr(node.name)
        if not isinstance(name, Var):
            raise NotSupported("Non-var function name: '%s'" % (name,),
                               line=name.line)

        # Parse args
        args = self.visit(node.args) or []

        # Special cases (scanf & printf)
        if name.name == 'scanf':
            return self.visit_scanf(node, args)

        elif name.name == 'printf':
            return self.visit_printf(node, args)

        # Program functions
        elif name.name in self.fncs:
            return Op('FuncCall', name, *args, line=node.coord.line)

        # Library functions
        elif name.name in self.LIB_FNCS:
            return Op(name.name, *args, line=node.coord.line)

        else:
            raise NotSupported(
                "Unsupported function call: '%s'" % (name.name,),
                line=node.coord.line)
예제 #4
0
파일: parser.py 프로젝트: iradicek/clara
 def getretcond(self, expr):
     if isinstance(expr, Op) and expr.name == 'ite':
         icond = expr.args[0]
         ct = self.getretcond(expr.args[1])
         cf = self.getretcond(expr.args[2])
         cond = []
         if ct is None and cf is None:
             return None
         if ct is True and cf is True:
             return True
         if ct:
             if ct is True:
                 cond.append(icond.copy())
             else:
                 cond.append(Op(self.ANDOP, icond.copy(), ct.copy()))
         if cf:
             nicond = Op(self.NOTOP, icond)
             if cf is True:
                 cond.append(nicond.copy())
             else:
                 cond.append(Op(self.ANDOP, nicond.copy(), cf.copy()))
         if len(cond) == 1:
             return cond[0]
         else:
             return Op(self.OROP, cond[0], cond[1])
         
     elif isinstance(expr, Var) and expr.name == VAR_RET:
         return None
     
     else:
         return True
예제 #5
0
    def visit_UnaryOp(self, node):
        '''
        UnaryOp - unary operation
        Attrs: op, expr
        '''

        expr = self.visit_expr(node.expr)

        # Special cases
        # ++/--
        if node.op in ['++', '--']:
            if not isinstance(expr, Var):
                raise NotSupported('++/-- supported only for Vars',
                                   line=node.coord.line)
            self.addexpr(expr.name,
                         Op(node.op[1], expr.copy(), Const('1'),
                            line=node.coord.line))
            return expr
            
        elif node.op in ['p++', 'p--']:
            if not isinstance(expr, Var):
                raise NotSupported('p++/p-- supported only for Vars',
                                   line=node.coord.line)
            self.addexpr(expr.name,
                         Op(node.op[1], expr.copy(), Const('1'),
                            line=node.coord.line))
            self.postincdec += 1
            return expr

        return Op(node.op, expr, line=node.coord.line)
예제 #6
0
파일: parser.py 프로젝트: ivantest22/clara
    def rmtmp(self, fnc):
        '''
        Removes (merges) "tmp" or SSA-generated assignments
        '''

        for loc in fnc.locs():

            m = {}
            exprs = []
            primed = set([])
            lastret = None

            # Remember "real" vars and replace temps
            for var, expr in fnc.exprs(loc):

                expr.prime(primed)

                for v, e in m.items():
                    expr = expr.replace(v, e)

                if var.endswith('&'):
                    m[var] = expr

                else:
                    if var == VAR_RET:
                        lastret = len(exprs)

                    exprs.append((var, expr))
                    primed.add(var)

            # "Merge" return stmts
            nexprs = []
            retexpr = None
            retcond = None
            for i, (var, expr) in enumerate(exprs):
                if var == VAR_RET:
                    tmpretcond = self.getretcond(expr)
                    if tmpretcond is True or retcond is None:
                        retcond = tmpretcond
                    elif tmpretcond is not None and retcond is not True:
                        retcond = Op(self.OROP, retcond, tmpretcond)
                    if retexpr:
                        retexpr = retexpr.replace(VAR_RET, expr)
                    else:
                        retexpr = expr

                    if i == lastret:
                        nexprs.append((var, retexpr))

                else:
                    if retcond is True:
                        continue
                    elif retcond:
                        expr = Op('ite', Op(self.NOTOP, retcond), expr,
                                  Var(var))
                    nexprs.append((var, expr))

            fnc.replaceexprs(loc, nexprs)
예제 #7
0
    def visit_BoolOp(self, node):
        func = node.op.__class__.__name__
        val_model = map(self.visit_expr, node.values)

        expr = Op(func, val_model[0], val_model[1], line=val_model[1].line)

        for v in val_model[2:]:
            expr = Op(func, expr, v, line=v.line)

        return expr
예제 #8
0
    def visit_Assign(self, node):
        if len(node.targets) != 1:
            raise NotSupported('Only single assignments allowed')

        target = node.targets[0]

        # Assignment to a variable
        if isinstance(target, ast.Name):
            right = self.visit_expr(node.value)
            self.addtype(target.id, '*')
            self.addexpr(target.id, right)

        # Assignment to indexed element
        elif isinstance(target, ast.Subscript):
            if isinstance(target.slice, ast.Index):
                var = Var(target.value.id)
                self.addtype(target.value.id, '*')
                right = self.visit_expr(node.value)
                index = self.visit_expr(target.slice.value)

                self.addexpr(
                    target.value.id,
                    Op('AssignElement', var, index, right, line=right.line))

            else:
                raise NotSupported(
                    'Subscript assignments only allowed to Indices',
                    line=node.lineno)

        # Assignment to a tuple
        elif isinstance(target, ast.Tuple):
            targets = map(self.visit_expr, target.elts)
            right = self.visit_expr(node.value)
            for i, target in enumerate(targets):
                expr = Op('GetElement',
                          right.copy(),
                          Const(str(i)),
                          line=right.line)
                if isinstance(target, Var):
                    self.addexpr(target.name, expr)
                else:
                    raise NotSupported("Tuple non-var assignment",
                                       line=target.line)

        else:
            raise NotSupported('Assignments to {} not supported'.format(
                target.__class__.__name__),
                               line=node.lineno)
예제 #9
0
    def visit_Assignment(self, node):
        '''
        Assignment
        Attrs: op, lvalue, rvalue
        '''

        lvalue = self.visit_expr(node.lvalue)
        postincdec = self.postincdec
        self.postincdec = 0
        rvalue = self.visit(node.rvalue)
        postincdec, self.postincdec = self.postincdec, postincdec

        if not rvalue:
            rvalue = Const('?', line=node.coord.line)
        
        # Cases of assignment operator
        if node.op == '=':
            pass
        elif len(node.op) == 2 and node.op[1] == '=':
            rvalue = Op(node.op[0], lvalue.copy(), rvalue, line=rvalue.line)
        else:
            raise NotSupported("Assignment operator: '%s'" % (node.op,),
                               line=node.coord.line)

        # Distinguish lvalue (ID and Array)
        if isinstance(lvalue, Var):
            lval = lvalue
        
        elif (isinstance(lvalue, Op) and lvalue.name == '[]'and
              isinstance(lvalue.args[0], Var)):
            rvalue = Op('ArrayAssign', lvalue.args[0].copy(),
                        lvalue.args[1].copy(), rvalue, line=node.coord.line)
            lval = lvalue.args[0]

        else:
            raise NotSupported("Assignment lvalue '%s'" % (lvalue,),
                               line=node.coord.line)

        # List of expression
        if isinstance(rvalue, list):
            rvalue = rvalue[-1]
        
        # Special case when previous assignment was p++/p--
        # push this assignment before the previous one
        self.addexpr(lval.name, rvalue.copy(),
                     idx=-postincdec if postincdec else None)

        return lvalue
예제 #10
0
    def visit_Decl(self, node):
        '''
        Decl - Declaration
        Attrs: name, quals, storage, funcspec, type, init, bitsize
        (using only: name, type & init)
        '''

        (name, type, dim) = self.visit(node.type)
        init = self.visit_expr(node.init, allownone=True)

        if not self.fncdef:
            try:
                self.addtype(name, type)
            except AssertionError:
                self.addwarn("Ignored global definition '%s' on line %s." % (
                    name, node.coord.line,))
                return

        if init and dim:
            raise NotSupported("Array Init & Create together",
                               line=node.coord.line)

        if init:
            self.addexpr(name, init)
            
        if dim:
            self.addexpr(name, Op('ArrayCreate', dim, line=dim.line))

        return (name, type, dim)
예제 #11
0
 def visit_InitList(self, node):
     '''
     Array Initialization List
     Attrs: exprs
     '''
     exprs = map(self.visit_expr, node.exprs or [])
     return Op('ArrayInit', *exprs, line=node.coord.line)
예제 #12
0
 def visit_Print(self, node):
     '''
     Only used in Python 2.x, ignores destination and newline
     '''
     values_model = map(self.visit_expr, node.values)
     expr = Op('StrAppend', Var(VAR_OUT), *values_model, line=node.lineno)
     self.addexpr(VAR_OUT, expr)
예제 #13
0
 def visit_Cast(self, node):
     '''
     Expression case
     Attrs: to_type, expr
     '''
     tt = self.visit(node.to_type)
     expr = self.visit_expr(node.expr)
     return Op('cast', Const(tt), expr, line=node.coord.line)
예제 #14
0
    def visit_BinaryOp(self, node):
        '''
        BinaryOp - binary operation
        Attrs: op, left, right
        '''

        return Op(node.op, self.visit_expr(node.left),
                  self.visit_expr(node.right), line=node.coord.line)
예제 #15
0
    def visit_Expr(self, node):
        '''
        Expressions need to be handled depending on their type.
        Method calls like str.lower() can be ignored
        (Strings are immutable), while
        calls like list.append() must be handled.
        '''
        if isinstance(node.value, ast.Call):
            if isinstance(node.value.func, ast.Name):
                self.warns.append('Ignored call to {} at line {}'.format(
                    node.value.func.id, node.lineno))

            elif isinstance(node.value.func, ast.Attribute):
                if node.value.func.attr in self.ATTR_FNCS:
                    call = self.visit_expr(node.value)
                    if isinstance(node.value.func.value, ast.Subscript):
                        var = self.visit_expr(node.value.func.value.value)
                        index = self.visit_expr(node.value.func.value.slice)
                        expr = Op('AssignElement',
                                  var,
                                  index,
                                  call,
                                  line=node.lineno)
                        if isinstance(var, Var):
                            self.addexpr(var.name, expr)
                        else:
                            raise NotSupported("Non-name element assignment",
                                               line=node.lineno)

                    elif isinstance(node.value.func.value, ast.Name):
                        var = self.visit(node.value.func.value)
                        if isinstance(var, Var):
                            # Skip assignment of 'pop' function
                            if node.value.func.attr != 'pop':
                                self.addexpr(var.name, call)
                        else:
                            raise NotSupported("Non-name call",
                                               line=node.lineno)

                    else:
                        raise NotSupported('Call to {}'.format(
                            node.value.func.__class__.__name__),
                                           line=node.lineno)
                else:
                    self.warns.append('Ignored call to {} at line {}'.format(
                        node.value.func.attr, node.lineno))
            else:
                raise NotSupported('Call to {}'.format(
                    node.value.func.__class__.__name__),
                                   line=node.lineno)

        elif isinstance(node.value,
                        (ast.Num, ast.Str, ast.List, ast.Tuple, ast.Dict)):
            # Happily ignore these side-effect free statements
            pass
        else:
            self.warns.append('Ignored Expr of type {} at line {}'.format(
                node.value.__class__.__name__, node.lineno))
예제 #16
0
파일: parser.py 프로젝트: ivantest22/clara
    def getretcond(self, expr):
        if isinstance(expr, Op) and expr.name == 'ite':
            icond = expr.args[0]
            ct = self.getretcond(expr.args[1])
            cf = self.getretcond(expr.args[2])
            cond = []
            if ct is None and cf is None:
                return None
            if ct is True and cf is True:
                return True
            if ct:
                if ct is True:
                    cond.append(icond.copy())
                else:
                    cond.append(Op(self.ANDOP, icond.copy(), ct.copy()))
            if cf:
                nicond = Op(self.NOTOP, icond)
                if cf is True:
                    cond.append(nicond.copy())
                else:
                    cond.append(Op(self.ANDOP, nicond.copy(), cf.copy()))
            if len(cond) == 1:
                return cond[0]
            else:
                return Op(self.OROP, cond[0], cond[1])

        elif isinstance(expr, Var) and expr.name == VAR_RET:
            return None

        else:
            return True
예제 #17
0
파일: parser.py 프로젝트: ivantest22/clara
    def expr_list_and(self, exprs):

        if len(exprs) == 0:
            return None

        else:
            newexpr = exprs[0]
            for expr in exprs[1:]:
                newexpr = Op('&&', newexpr, expr, line=expr.line)
            return newexpr
예제 #18
0
    def visit_SetComp(self, node):
        elt = self.visit_expr(node.elt)

        if len(node.generators) != 1:
            raise NotSupported("Only one generator supported",
                               line=node.lineno)

        gen = self.visit_expr(node.generators[0])

        return Op('SetComp', elt, gen, line=node.lineno)
예제 #19
0
    def visit_Compare(self, node):
        comps_model = map(self.visit, node.comparators)
        ops_model = map(lambda x: x.__class__.__name__, node.ops)

        left = self.visit_expr(node.left)
        right = comps_model[0]
        op = ops_model[0]

        expr = Op(op, left, right, line=right.line)

        left = right
        for op, right in zip(ops_model[1:], comps_model[1:]):
            expr = Op('And',
                      expr,
                      Op(op, left, right, line=right.line),
                      line=right.line)
            left = right

        return expr
예제 #20
0
    def visit_DictComp(self, node):
        key = self.visit_expr(node.key)
        value = self.visit_expr(node.value)

        if len(node.generators) != 1:
            raise NotSupported("Only one generator supported",
                               line=node.lineno)

        gen = self.visit_expr(node.generators[0])

        return Op('DictComp', key, value, gen, line=node.lineno)
예제 #21
0
    def visit_ArrayRef(self, node):
        '''
        Array reference
        Attrs: name, subscript
        '''

        name = self.visit_expr(node.name)
        if not isinstance(name, Var):
            raise NotSupported("ArrayName: '%s'" % (name,))

        sub = self.visit_expr(node.subscript)

        return Op('[]', name, sub, line=node.coord.line)
예제 #22
0
 def visit_Slice(self, node):
     args = []
     if node.lower is None:
         args.append(Const('None'))
     else:
         args.append(self.visit_expr(node.lower))
     if node.upper is None:
         args.append(Const('None'))
     else:
         args.append(self.visit_expr(node.upper))
     if node.step is None:
         args.append(Const('None'))
     else:
         args.append(self.visit_expr(node.step))
     return Op('Slice', *args)
예제 #23
0
    def visit_comprehension(self, node):

        if node.ifs is None or len(node.ifs) == 0:
            ifs = Const('True')
        elif len(node.ifs) == 1:
            ifs = self.visit_expr(node.ifs[0])
        else:
            raise NotSupported("Comprehension multiple ifs")

        target = self.visit(node.target)
        if not self.islistofnames(target):
            raise NotSupported("Target is not a list of names")

        iter = self.visit(node.iter)

        return Op('Comp', target, iter, ifs)
예제 #24
0
파일: parser.py 프로젝트: yxliang01/clara
    def optimizeif(self, preloc, condexpr, trueloc, falseloc):
        '''
        Optimized "simple" or "loop-less" if statement
        '''

        # Remove unneded part of the graph
        self.fnc.rmtrans(preloc, True)
        self.loc = preloc

        # Keep track of assigned vars
        varss = set()
        varsl = []
        mt = {}
        mf = {}

        # Add exprs from branches
        def addvars(loc, m):
            for (var, expr) in self.fnc.exprs(loc):
                newvar = self.ssavar(var)

                if var not in varss:
                    varss.add(var)
                    varsl.append(var)

                # Replace vars mapped so far
                for (v1, v2) in m.items():
                    expr = expr.replace(v1, Var(v2))
                expr.original = (var, self.cnt)
                self.addexpr(newvar, expr)

                # Remember replacement
                m[var] = newvar

        addvars(trueloc, mt)
        if falseloc is not None:
            addvars(falseloc, mf)

        # Add condition
        condvar = self.ssavar('$cond')
        self.addexpr(condvar, condexpr.copy())

        # Merge branches
        for var in varsl:
            self.addexpr(
                var,
                Op('ite', Var(condvar), Var(mt.get(var, var)),
                   Var(mf.get(var, var))))
예제 #25
0
    def visit_TernaryOp(self, node):
        '''
        Ternary Operator node
        Attrs: cond, iftrue, iffalse
        '''

        cond = self.visit_expr(node.cond)

        n = self.numexprs()
        ift = self.visit_expr(node.iftrue)
        iff = self.visit_expr(node.iffalse)

        if self.numexprs() > n:
            self.rmlastexprs(num=self.numexprs() - n)
            return self.visit_if(node, node.cond, node.iftrue, node.iffalse)

        return Op('ite', cond, ift, iff, line=node.coord.line)
예제 #26
0
    def visit_Call(self, node):
        if len(node.keywords) > 0 or node.starargs or node.kwargs:
            raise NotSupported(
                'starargs, kwargs and keyword arguments not supported',
                line=node.lineno)

        if isinstance(node.func, ast.Name):
            if node.func.id in self.BUILTIN_FNCS:
                fncname = node.func.id
                args = list(map(self.visit_expr, node.args))
                return Op(fncname, *args, line=node.lineno)
            else:
                fnc = Var(node.func.id)
                args = list(map(self.visit_expr, node.args))
                return Op('FuncCall', fnc, *args, line=node.lineno)

        elif isinstance(node.func, ast.Num):
            num = self.visit_expr(node.func)
            self.addwarn("Call to a number '%s' on line %s ignored", num,
                         num.line)
            return Const('?')

        elif isinstance(node.func, ast.Attribute):
            attr = node.func.attr
            val = self.visit_expr(node.func.value)
            args = list(map(self.visit_expr, node.args))
            if isinstance(val, Var) and val.name in self.MODULE_NAMES:
                return Op('%s_%s' % (val, attr), *args, line=node.lineno)
            if attr == 'pop':
                if isinstance(val, Var):
                    popvar = self.ssavar('pop#')
                    self.addexpr(popvar, Op(attr, val, *args,
                                            line=node.lineno))
                    self.addexpr(val.name,
                                 Op('GetElement', Var(popvar), Const('0')))
                    return Op('GetElement', Var(popvar), Const('1'))
                else:
                    raise NotSupported('Pop to a non-name list')
            return Op(attr, val, *args, line=node.lineno)

        else:
            raise NotSupported('Call of {} not supported'.format(
                node.func.__class__.__name__),
                               line=node.lineno)
예제 #27
0
    def visit_Delete(self, node):
        if len(node.targets) > 1:
            raise NotSupported('Multiple delete targets')
        target = self.visit(node.targets[0])

        if isinstance(target, Op):
            if target.name == 'GetElement':
                if isinstance(target.args[0], Var):
                    if len(target.args) != 2:
                        raise NotSupported('Delete target with %d args' %
                                           (len(target.args, )))
                    delexpr = Op('Delete', *target.args, line=node.lineno)
                    self.addexpr(target.args[0].name, delexpr)
                else:
                    raise NotSupported('Delete target not Var, but %s' %
                                       (target.args[0].__class__))
            else:
                raise NotSupported('Delete target op: %s' % (target.name, ))
        else:
            raise NotSupported('Delete target: %s' % (target.__class__, ))
예제 #28
0
    def visit_For(self, node):

        if node.orelse:
            raise NotSupported("For-Else not supported",
                               line=self.getline(node.orelse))

        # Iterated expression
        it = self.visit_expr(node.iter)

        # Targets of iteration
        if isinstance(node.target, ast.Name):
            targets = [self.visit_expr(node.target)]
        elif isinstance(node.target, ast.Tuple):
            targets = map(self.visit_expr, node.target.elts)
        else:
            raise NotSupported('For loop with {} as target'.format(
                node.target.__class__.__name__),
                               line=node.lineno)

        hiddenvar = self.hiddenvarcnt
        self.hiddenvarcnt += 1

        # Set up the iterated variable
        iter_name = 'iter#{}'.format(hiddenvar)
        it_var = Var(iter_name)
        self.addtype(iter_name, '*')

        # Set up the iteration index
        ind_name = 'ind#{}'.format(hiddenvar)
        ind_var = Var(ind_name)
        self.addtype(ind_name, 'int')

        # Add assignments to iterators
        self.addexpr(it_var.name, it)
        self.addexpr(ind_var.name, Const(str(0), line=node.lineno))

        # Condition is ind_var < len(iter_var)
        cond = Op('Lt',
                  ind_var.copy(),
                  Op('len', it_var.copy()),
                  line=node.iter.lineno)

        # Assignments to iterated variable(s)
        prebody = []
        el = Op('GetElement',
                it_var.copy(),
                ind_var.copy(),
                line=node.target.lineno)
        if len(targets) == 1:
            prebody.append((targets[0].name, el.copy()))
        else:
            for i, t in enumerate(targets):
                eli = Op('GetElement',
                         el.copy(),
                         Const(str(i)),
                         line=node.target.lineno)
                prebody.append((t.name, eli))

        # Add index variable increment
        prebody.append((ind_var.name,
                        Op('Add',
                           ind_var.copy(),
                           Const(str(1)),
                           line=node.iter.lineno)))

        self.visit_loop(node,
                        None,
                        cond,
                        None,
                        node.body,
                        False,
                        'for',
                        prebody=prebody)
예제 #29
0
 def visit_Subscript(self, node):
     val = self.visit_expr(node.value)
     return Op('GetElement',
               val,
               self.visit_expr(node.slice),
               line=node.lineno)
예제 #30
0
 def visit_Set(self, node):
     elts = map(self.visit_expr, node.elts)
     return Op('SetInit', *elts, line=node.lineno)
예제 #31
0
 def visit_Dict(self, node):
     keys = map(self.visit_expr, node.keys)
     vals = map(self.visit_expr, node.values)
     args = list(chain(*zip(keys, vals)))
     return Op('DictInit', *args, line=node.lineno)
예제 #32
0
파일: py_parser.py 프로젝트: iradicek/clara
    def visit_For(self, node):
        
        if node.orelse:
            raise NotSupported("For-Else not supported",
                               line=self.getline(node.orelse))
        
        # Iterated expression
        it = self.visit_expr(node.iter)

        # Targets of iteration
        if isinstance(node.target, ast.Name):
            self.addtype(node.target.id, '*')
            targets = [self.visit_expr(node.target)]
        elif isinstance(node.target, ast.Tuple):
            for el in node.target.elts:
                if isinstance(el, ast.Name):
                    self.addtype(el.id, '*')
            targets = map(self.visit_expr, node.target.elts)
        else:
            raise NotSupported(
                'For loop with {} as target'.format(
                    node.target.__class__.__name__),
                line=node.lineno)

        hiddenvar = self.hiddenvarcnt
        self.hiddenvarcnt += 1

        # Set up the iterated variable
        iter_name = 'iter#{}'.format(hiddenvar)
        it_var = Var(iter_name)
        self.addtype(iter_name, '*')

        # Set up the iteration index
        ind_name = 'ind#{}'.format(hiddenvar)
        ind_var = Var(ind_name)
        self.addtype(ind_name, 'int')

        # Add assignments to iterators
        self.addexpr(it_var.name, it)
        self.addexpr(ind_var.name, Const(str(0), line=node.lineno))

        # Condition is ind_var < len(iter_var)
        cond = Op('Lt', ind_var.copy(), Op('len', it_var.copy()),
                  line=node.iter.lineno)
                  
        # Assignments to iterated variable(s)
        prebody = []
        el = Op('GetElement', it_var.copy(), ind_var.copy(),
                line=node.target.lineno)
        if len(targets) == 1:
            prebody.append((targets[0].name, el.copy()))
        else:
            for i, t in enumerate(targets):
                eli = Op('GetElement', el.copy(), Const(str(i)),
                         line=node.target.lineno)
                prebody.append((t.name, eli))
        
        # Add index variable increment
        prebody.append((ind_var.name,
                        Op('Add', ind_var.copy(), Const(str(1)),
                           line=node.iter.lineno)))

        self.visit_loop(node, None, cond, None, node.body, False, 'for',
                        prebody=prebody)