Example #1
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)
Example #2
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)
Example #3
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
Example #4
0
 def visit_Num(self, node):
     if type(node.n) in (int, float, long, complex):
         return Const(str(node.n), line=node.lineno)
     else:
         raise NotSupported('Type {} not supported'.format(
             type(node.n).__name__),
                            line=node.lineno)
Example #5
0
    def visit_expr(self, node, allowlist=False, allownone=False):
        res = self.visit(node)

        if isinstance(res, list) and allowlist:
            ok = True
            for r in res:
                if not isinstance(r, Expr):
                    ok = False
                    break
            if ok:
                return res

        if res and not isinstance(res, Expr):
            raise ParseError("Expected expression, got '%s'" % (res, ),
                             line=node.coord.line)

        if (not res) and (not allownone):
            if node:
                self.addwarn("Expression expected at line %s" %
                             (node.coord.line, ))
            else:
                self.addwarn("Expression expected")
            res = Const('?')

        return res
Example #6
0
    def visit_Return(self, node):
        if node.value is None:
            ret = Const('None', line=node.lineno)
        else:
            ret = self.visit_expr(node.value)

        self.addexpr(VAR_RET, ret)
Example #7
0
    def visit_Constant(self, node):
        '''
        Constant
        Attrs: type, value
        '''

        return Const(node.value, line=node.coord.line)
Example #8
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)
Example #9
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)
Example #10
0
    def visit_ID(self, node):
        '''
        ID
        Attrs: name
        '''

        if node.name in self.CONSTS:
            return Const(node.name, line=node.coord.line)

        return Var(node.name, line=node.coord.line)
Example #11
0
    def visit_Return(self, node):
        '''
        Return node
        Attrs: expr
        '''

        expr = self.visit_expr(node.expr)
        if not expr:
            expr = Const('top', line=node.coord.line)
        self.addexpr(VAR_RET, expr)
Example #12
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)
Example #13
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)
Example #14
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)
Example #15
0
    def visit_loop(self, node, init, cond, next, body, do, name, prebody=None):

        # Visit init stmts
        if init:
            self.visit(init)

        # Add condition (with new location)
        preloc = self.loc
        if isinstance(cond, Expr):
            condexpr = cond
        else:
            condexpr = self.visit_expr(cond, allowlist=True)
            if isinstance(condexpr, list):
                condexpr = self.expr_list_and(condexpr)

        if not condexpr:
            condexpr = Const('1')
        condloc = self.addloc("the condition of the '%s' loop at line %s" %
                              (name, condexpr.line or self.getline(node)))
        self.addexpr(VAR_COND, condexpr)

        # Add exit loc
        exitloc = self.addloc("*after* the '%s' loop starting at line %d" %
                              (name, self.getline(node)))

        # Add body with (new location)
        bodyloc = self.addloc(
            "inside the body of the '%s' loop beginning at line %d" %
            (name, self.getline(body) or self.getline(node)))
        self.addloop((condloc, exitloc))
        if prebody:
            map(lambda x: self.addexpr(*x), prebody)
        self.visit(body)
        if next:
            self.visit(next)
        self.poploop()
        afterloc = self.loc

        # Connect transitions
        self.addtrans(preloc, True, bodyloc if do else condloc)
        self.addtrans(condloc, True, bodyloc)
        self.addtrans(condloc, False, exitloc)
        self.addtrans(afterloc, True, condloc)

        self.loc = exitloc
Example #16
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)
Example #17
0
    def visit_scanf(self, node, args):
        '''
        scanf function call
        '''

        # Check format
        if len(args) == 0:
            self.warn("'scanf' without arguments at line %s (ignored)",
                      node.coord.line)
        else:
            fmt = args[0]

            if isinstance(fmt, Const) and fmt.value[0] == '"' \
               and fmt.value[-1] == '"':
                fmt = fmt.value[1:-1]
                args = args[1:]
            else:
                self.warn("First argument of 'scanf' at line %s should be a \
(string) format (ignored)",
                          node.coord.line)
                fmt = ''
                args = []

        # Extract format arguments
        fs = list(re.findall(
            r'(%((d)|(i)|(li)|(lli)|(ld)|(lld)|(lf)|(f)|(s)|(c)))', fmt))

        # Check argument number
        if len(fs) != len(args):
            self.addwarn("Mismatch between format and number of argument(s)\
of 'scanf' at line %s.",
                         node.coord.line)

            if len(args) > len(fs):
                fs += ['*' for _ in xrange(len(args) - len(fs))]

        # Iterate formats and arguments
        for f, a in zip(fs, args):

            if f:
                f = f[0]

            # Get type from an argument
            if f in ['%d', '%ld', '%i', '%li', '%lli', '%lld']:
                t = 'int'
            elif f in ['%c']:
                t = 'char'
            elif f in ['%s']:
                t = 'string'
            elif f in ['%f', '%lf']:
                t = 'float'
            elif f == '*':
                t = '*'
            else:
                self.addwarn("Invalid 'scanf' format at line %s.",
                             node.coord.line)
                t = '*'

            # Check argument type
            if isinstance(a, Op) and a.name == '&' and len(a.args) == 1:
                a = a.args[0]

            elif isinstance(a, Var) or (isinstance(a, Op) and a.name == '[]'):
                self.addwarn("Forgoten '&' in 'scanf' at line %s?",
                             node.coord.line)

            else:
                raise NotSupported("Argument to scanf: '%s'" % (a,),
                                   line=node.coord.line)

            # Add operations
            rexpr = Op('ListHead', Const(t), Var(VAR_IN), line=node.coord.line)
            if isinstance(a, Var):
                self.addexpr(a.name, rexpr)
            elif isinstance(a, Op) and a.name == '[]' and isinstance(a.args[0],
                                                                     Var):
                self.addexpr(a.args[0].name,
                             Op('ArrayAssign', a.args[0], a.args[1], rexpr,
                                line=node.coord.line))
            else:
                raise NotSupported("Argument to scanf: '%s'" % (a,),
                                   line=node.coord.line)
            self.addexpr(VAR_IN,
                         Op('ListTail', Var(VAR_IN), line=node.coord.line))
Example #18
0
 def visit_Attribute(self, node):
     value = self.visit(node.value)
     return Op('GetAttr', value, Const(node.attr), line=node.lineno)
Example #19
0
 def visit_Str(self, node):
     return Const('"{}"'.format(node.s), line=node.lineno)
Example #20
0
 def visit_Name(self, node):
     if node.id in self.CONSTS:
         return Const(node.id)
     self.addtype(node.id, '*')
     return Var(node.id)