Ejemplo n.º 1
0
def analyseexpr(expr,context,warn):
    t = _analyseexpr(expr,context,warn)
    if not t:
        print('{0} has undefined type.'.format(parser.prettyexpr(expr)))
        return ErrorType()
    else:
        return t
Ejemplo n.º 2
0
def _analyseexpr(expr,context,warn):
    ''' Simulate execution of the given expression in the given
    context, and return the expression's return type. (The context may
    get modified during this call).

    Disable warn if the expression having no defined value is not
    a problem (e.g. when analysing an expression whose value is not
    used) '''
    if not expr:
        print('Skipping broken expression')
        return ErrorType()
    if expr[0][0] in tokens.binaryoperators:
        # The if is to prevent that warning about uninitialised
        # variables for lhs of assignments.
        if expr[0][0]==tokens.Assign:
            ptypes = [MixedType()] + [
                analyseexpr(e,context,warn) for e in expr[2:] ]
        else:
            ptypes = [ analyseexpr(e,context,warn) for e in expr[1:] ]
        # 1. Compute the returned value "rtype"

        if expr[0][0]==tokens.Assign:
            rtype = ptypes[1]
        elif expr[0][0] in [tokens.Minus,tokens.MinusAssign,tokens.Plus,tokens.PlusAssign,
                        tokens.Times,tokens.Divide,tokens.Modulo]:
            # Numerical operations
            rtype = TrustedType(PrimType('num'))
            for param in ptypes:
                rtype = rtype | param.cast('num')
        elif expr[0][0] in [tokens.Period, tokens.CatAssign]:
            # String operations
            rtype = TrustedType(PrimType('string'))
            for param in ptypes:
                rtype = rtype | param.cast('string')
        else:
            rtype = MixedType()
        # 2. Perform the assignment, if any
        if expr[0][0] in [tokens.MinusAssign, tokens.PlusAssign, tokens.CatAssign, tokens.Assign]:
            if expr[1][0][0]==tokens.Variable:
                context.settype(expr[1][0][1],rtype)
            else:
                warn.warning('Unrecognised l-value, skipping assignment')
        return rtype
    elif expr[0][0] in tokens.unaryoperators or expr[0][0] == tokens.Type:
        analyseexpr(expr[1],context,warn)
    elif expr[0][0] == tokens.Question:
        analyseexpr(expr[1],context,warn)
        analyseexpr(expr[2],context,warn)
        analyseexpr(expr[3],context,warn)
    elif expr[0][0] == tokens.String:
        return TrustedType(PrimType('string'))
    elif expr[0][0] == tokens.Number:
        return TrustedType(PrimType('num'))
    elif expr[0][0] == tokens.BuiltinConstant:
        return TrustedType(PrimType('boolean'))
    elif expr[0][0] == tokens.Variable:
        return context.gettype(expr[0][1],warn.on())
    elif expr[0][0] == tokens.FunctionCall:
        ptypes = [ analyseexpr(e,context,warn) for e in expr[2:] ]
        if expr[1][1] == 'define':
            if expr[2][0][0] == tokens.String:
                consts[expr[2][0][1]] = ptypes[1]
            else:
                warn.warning('lhs of {0} not a constant string, ignoring.'.format(parser.prettyexpr(expr)))
            return UnsetType()
        elif expr[1][1] == 'array':
            # Can't make this a builtin function because of the
            # unlimited argument count...
            r = EmptyType()
            for ptype in ptypes:
                # print('r = {0} | {1}'.format(r,ptype))
                r = r | ptype

            return ArrType(r)
        else:
            fname = expr[1][1]
            if fname in funcs:
                return funcs[fname].apply(context,ptypes,warn)
            elif fname in consts:
                return consts[fname]
            else:
                warn.warning("calling undefined function {0}.".format(fname))
                return ErrorType()

            # return ReturnedType(expr[1][1], ptypes).reduce()
    elif expr[0][0] == tokens.ArrayAccess:
        ptypes = [ analyseexpr(e,context,warn) for e in expr[1:] ]
        return ptypes[0].arrayelttype(warn)
    else:
        return MixedType()