Exemplo n.º 1
0
 def check_type(old_type, new_type):
     if new_type == old_type:
         return old_type
     elif new_type == u.String():
         if must_be_number:
             raise exception.BananaTypeError(expected_type=u.Number,
                                             found_type=new_type)
         if old_type is None:
             return new_type
         elif u.can_to_str(old_type):
             return new_type
         else:
             raise exception.BananaTypeError(expected_type=old_type,
                                             found_type=new_type)
     elif new_type == u.Number():
         if old_type is None:
             return new_type
         elif old_type == u.String():
             return old_type
         elif not old_type == u.Number():
             raise exception.BananaTypeError(expected_type=old_type,
                                             found_type=new_type)
     else:
         raise exception.BananaTypeError(expected_type=old_type,
                                         found_type=new_type)
Exemplo n.º 2
0
def typeck_connections(connection, type_table):
    """
    Once all variable have been type-checked, we can
    try to type-check connections.
    :type connection: monasca_analytics.banana.grammar.ast.Connection
    :param connection: The connection to type-check
    :type type_table: monasca_analytics.banana.typeck.type_table.TypeTable
    :param type_table: The table with all variable already type-checked.
    :raise Raise an exception if there's a type error in connections.
    """
    if connection is not None:
        for ident_from, ident_to in connection.connections:
            type_from = type_table.get_type(ident_from)
            type_to = type_table.get_type(ident_to)
            if not util.is_comp(type_from):
                raise exception.BananaTypeError(expected_type=util.Component(),
                                                found_type=type_from)
            if not util.is_comp(type_to):
                raise exception.BananaTypeError(expected_type=util.Component(),
                                                found_type=type_to)
            if type(type_to) not in valid_connections_types[type(type_from)]:
                possible_types = map(lambda x: x.__name__,
                                     valid_connections_types[type(type_from)])
                raise exception.BananaConnectionError(connection.span,
                                                      ident_from, ident_to,
                                                      type_from,
                                                      possible_types)
Exemplo n.º 3
0
def attach_to_root(root_obj, obj1, span, erase_existing=False):
    """
    Attach the object obj1 to the root_obj object type.

    :type root_obj: Object
    :param root_obj: The root object
    :type obj1: Object
    :param obj1: The object to attach.
    :type span: Span
    :param span: The span for this change.
    :type erase_existing: bool
    :param erase_existing: Set to true if the root type should
                           always be erased.
    """
    for key, child_type in obj1.props.iteritems():
        if key in root_obj.props:
            root_sub_type = root_obj.props[key]
            # Both are object -> recurse
            if isinstance(root_sub_type, Object) and\
               isinstance(child_type, Object):
                attach_to_root(root_sub_type, child_type, span, erase_existing)
            elif erase_existing:
                root_obj.props[key] = child_type
            else:
                raise exception.BananaTypeError(expected_type=root_sub_type,
                                                found_type=child_type,
                                                span=span)
        else:
            # We can simply attach the new type!
            root_obj.props[key] = child_type
Exemplo n.º 4
0
    def set_type(self, var, _type, statement_index):
        """
        Set the type for the given var to _type.

        :type var: ast.Ident | ast.DotPath
        :param var: The var to set a type.
        :type _type: util.Object | util.Component | util.String | util.Number
        :param _type: The type for the var.
        :type statement_index: int
        :param statement_index: The statement at which this assignment was
                                made.
        """
        if _type is None:
            raise exception.BananaTypeCheckerBug(
                "'None' is not a valid banana type"
            )

        if isinstance(var, ast.Ident):
            self._check_needs_for_snapshot(var, _type, statement_index)
            self._variables[var] = _type
            return

        if isinstance(var, ast.DotPath):
            if util.is_comp(_type) and len(var.properties) > 0:
                raise exception.BananaAssignCompError(var.span)

            if len(var.properties) == 0:
                self._check_needs_for_snapshot(
                    var.varname,
                    _type,
                    statement_index
                )
                self._variables[var.varname] = _type
            else:
                if var.varname in self._variables:
                    var_type = self._variables[var.varname]
                    if isinstance(var_type, util.Object):
                        new_type = util.create_object_tree(
                            var.next_dot_path(), _type)
                        util.attach_to_root(var_type, new_type, var.span,
                                            erase_existing=True)
                    elif isinstance(var_type, util.Component):
                        var_type[var.next_dot_path()] = _type
                    else:
                        raise exception.BananaTypeError(
                            expected_type=util.Object,
                            found_type=type(var)
                        )
                # Var undeclared, declare its own type
                else:
                    new_type = util.create_object_tree(var.next_dot_path(),
                                                       _type)
                    self._variables[var.varname] = new_type
            return
        raise exception.BananaTypeCheckerBug("Unreachable code reached.")
Exemplo n.º 5
0
def typeck_expr(expr, type_table):
    """
    Type-check the given expression. If the typecheck
    pass, the resulting type will be used for the strategy
    to use when evaluating this expression.
    :type expr: ast.Expr
    :param expr: The expression to typecheck.
    :type type_table: typetbl.TypeTable
    :param type_table: Type of the table
    :rtype: u.Number | u.String
    :return: Returns the type of the expression if possible
    :raise: Raise an exception
    """
    # In the case where we are just wrapping around
    # only one expression, the logic below
    # needs to be skipped.
    if len(expr.expr_tree) == 1:
        return typeck_rhs(expr.expr_tree[0], type_table)

    _type = None
    must_be_number = False

    def check_type(old_type, new_type):
        if new_type == old_type:
            return old_type
        elif new_type == u.String():
            if must_be_number:
                raise exception.BananaTypeError(expected_type=u.Number,
                                                found_type=new_type)
            if old_type is None:
                return new_type
            elif u.can_to_str(old_type):
                return new_type
            else:
                raise exception.BananaTypeError(expected_type=old_type,
                                                found_type=new_type)
        elif new_type == u.Number():
            if old_type is None:
                return new_type
            elif old_type == u.String():
                return old_type
            elif not old_type == u.Number():
                raise exception.BananaTypeError(expected_type=old_type,
                                                found_type=new_type)
        else:
            raise exception.BananaTypeError(expected_type=old_type,
                                            found_type=new_type)

    def allowed_symbol(current_type):
        if current_type == u.String():
            return ['+']
        else:
            return ['+', '-', '*', '/']

    for el in expr.expr_tree:
        if isinstance(el, ast.StringLit):
            _type = check_type(_type, u.String())
        elif isinstance(el, ast.Number):
            _type = check_type(_type, u.Number())
        elif isinstance(el, ast.Ident):
            ident_type = type_table.get_type(el)
            _type = check_type(_type, ident_type)
        elif isinstance(el, ast.DotPath):
            dotpath_type = type_table.get_type(el)
            _type = check_type(_type, dotpath_type)
        elif isinstance(el, ast.Expr):
            _type = check_type(_type, typeck_expr(el, type_table))
        elif isinstance(el, basestring):
            if el not in allowed_symbol(_type):
                raise exception.BananaUnknownOperator(expr.span, el, _type)
            if el in ['-', '*', '/']:
                must_be_number = True
        else:
            raise exception.BananaTypeError(expected_type=[
                u.Number.__name__, u.String.__name__, u.Object.__name__
            ], )

    # The final type if we made until here!
    return _type