예제 #1
0
    def check_semantics(self, scope, errors):
        """
        Para obtener información acerca de los parámetros recibidos por este método 
        consulte la documentación del método C{check_semantics} en la clase 
        C{LanguageNode}.
        
        El operador menos unario se aplica solamente a expresiones que devuelvan
        enteros y el tipo de retorno siempre será entero.
        
        En la comprobación semántica de este nodo del árbol de sintáxis abstracta 
        se comprueba que la expresión a la que se le va aplicar el operador menos 
        unario esté correcta semánticamente y que tenga valor de retorno entero. 
        El tipo del valor de retorno de la expresión representada por este nodo
        siempre será C{IntegerType}.
        """
        self._scope = scope
        
        errors_before = len(errors)
        
        self.expression.check_semantics(scope, errors)
        
        if errors_before == len(errors):
            if self.expression.has_return_value():
                if self.expression.return_type != IntegerType():
                    message = 'The expression of the unary minus operator at line {line} ' \
                              'does not return an integer value'
                    errors.append(message.format(line=self.line_number))
            else:
                message = 'The expression of the unary minus operator at line {line} ' \
                          'does not return a value'
                errors.append(message.format(line=self.line_number))

        self._return_type = IntegerType()
    def check_semantics(self, scope, errors):
        """
        Para obtener información acerca de los parámetros recibidos por este método
        consulte la documentación del método C{check_semantics} en la clase 
        C{LanguageNode}.
        
        Los operadores cuyas clases del árbol de sintáxis abstracta derivan de esta
        deben recibir en ambos operandos números enteros o ambos cadenas de 
        caracteres. Siempre tienen tipo de retorno entero (1 para el resultado 
        verdadero, 0 para el falso).
        
        En la comprobación semántica de este nodo del árbol de sintáxis abstracta
        se comprueban semánticamente tanto la expresión de la izquierda como la 
        expresión de la derecha. Luego se comprueba que ambas retornen valor y 
        que el tipo de retorno de ambas sea enteros o cadenas de caracteres.
        """
        self._scope = scope

        valid_types = (IntegerType(), StringType())

        errors_before = len(errors)

        self.right.check_semantics(scope, errors)

        if errors_before == len(errors):
            if self.right.has_return_value():
                if self.right.return_type not in valid_types:
                    message = 'Invalid type of right operand in the binary ' \
                              'relational operator at line {line}'
                    errors.append(message.format(line=self.line_number))
            else:
                message = 'Invalid use of binary relational operator with a ' \
                          'non-valued right expression at line {line}'
                errors.append(message.format(line=self.line_number))

        errors_before = len(errors)

        self.left.check_semantics(scope, errors)

        if errors_before == len(errors):
            if self.left.has_return_value():
                if self.left.return_type not in valid_types:
                    message = 'Invalid type of left operand in the binary ' \
                              'relational operator at line {line}'
                    errors.append(message.format(line=self.line_number))
            else:
                message = 'Invalid use of binary relational operator with a ' \
                          'non-valued left expression at line {line}'
                errors.append(message.format(line=self.line_number))

            if self.right.return_type != self.left.return_type:
                message = 'Types of left and right operands of the binary ' \
                          'relational operator at line {line} does not match'
                errors.append(message.format(line=self.line_number))

        self._return_type = IntegerType()
예제 #3
0
    def generate_code(self, generator):
        """
        Genera el código C correspondiente a la estructura del lenguaje Tiger
        representada por el nodo.

        @type generator: C{CodeGenerator}
        @param generator: Clase auxiliar utilizada en la generación del 
            código C correspondiente a un programa Tiger.        
        
        @raise CodeGenerationError: Esta excepción se lanzará cuando se produzca
            algún error durante la generación del código correspondiente al nodo.
            La excepción contendrá información acerca del error.
        """
        self.scope.generate_code(generator)
        self.left.generate_code(generator)
        self.right.generate_code(generator)
        result_var = generator.define_local(IntegerType().code_type)
        if isinstance(self.left.return_type, StringType):
            stmt = '{result} = (pytiger2c_strcmp({left}, {right}) {op} 0);'
        elif isinstance(self.left, NilType):
            stmt = '{result} = ((({left_type}) {left}) {op} {right});'
        elif isinstance(self.right, NilType):
            stmt = '{result} = ({left} {op} (({right_type}) {right}));'
        else:
            stmt = '{result} = ({left} {op} {right});'
        stmt = stmt.format(result=result_var, 
                           op=self._code_operator,
                           left=self.left.code_name, 
                           right=self.right.code_name,
                           left_type=self.left.return_type.code_type,
                           right_type=self.right.return_type.code_type)
        generator.add_statement(stmt)
        self._code_name = result_var
예제 #4
0
    def generate_code(self, generator):
        """
        Genera el código C correspondiente a la estructura del lenguaje Tiger
        representada por el nodo.

        @type generator: C{CodeGenerator}
        @param generator: Clase auxiliar utilizada en la generación del 
            código C correspondiente a un programa Tiger.        
        
        @raise CodeGenerationError: Esta excepción se lanzará cuando se produzca
            algún error durante la generación del código correspondiente al nodo.
            La excepción contendrá información acerca del error.
        """
        self.scope.generate_code(generator)
        result_var = generator.define_local(IntegerType().code_type)
        self.left.generate_code(generator)
        generator.add_statement(
            'if ({left}) {{'.format(left=self.left.code_name))
        generator.add_statement('{result} = 1; }}'.format(result=result_var))
        generator.add_statement('else {')
        self.right.generate_code(generator)
        generator.add_statement(
            'if ({right}) {{'.format(right=self.right.code_name))
        generator.add_statement('{result} = 1; }}'.format(result=result_var))
        generator.add_statement('else {')
        generator.add_statement('{result} = 0; }}'.format(result=result_var))
        generator.add_statement('}')
        self._code_name = result_var
예제 #5
0
 def _init_types(self):
     """
     Inicializa los tipos básicos del lenguaje Tiger definidos implícitamente 
     en el ámbito raíz.
     """
     self.define_type('int', IntegerType())
     self.define_type('string', StringType())
예제 #6
0
    def generate_code(self, generator):
        """
        Genera el código correspondiente a la estructura del lenguaje Tiger
        representada por el nodo.

        Para obtener información acerca de los parámetros recibidos por
        este método consulte la documentación del método C{generate_code}
        de la clase C{LanguageNode}.
        """
        self.scope.generate_code(generator)
        self.right.generate_code(generator)
        self.left.generate_code(generator)
        # Check integer division by zero.
        statement = 'if({var} == 0) {{ pytiger2c_error("{msg}"); }}'
        statement = statement.format(var=self.right.code_name,
                                     msg="Integer division by zero.")
        generator.add_statement(statement)
        int_code_type = IntegerType().code_type
        local_var = generator.define_local(int_code_type)
        statement = '{var} = {left} {operator} {right};'
        statement = statement.format(var=local_var,
                                     left=self.left.code_name,
                                     operator=self._operator,
                                     right=self.right.code_name)
        generator.add_statement(statement)
        self._code_name = local_var
예제 #7
0
    def check_semantics(self, scope, errors):
        """
        Para obtener información acerca de los parámetros recibidos por este método
        consulte la documentación del método C{check_semantics} en la clase 
        C{LanguageNode}.
        
        Los operadores cuyas clases del árbol de sintáxis abstracta derivan de esta
        deben recibir operandos enteros y siempre tendrán tipo de retorno entero
        (1 para el resultado verdadero, 0 para el falso).
        
        En la comprobación semántica de este nodo del árbol de sintáxis abstracta
        se comprueban semánticamente tanto la expresión de la izquierda como la 
        expresión de la derecha. Luego se comprueba que ambas retornen valor y 
        que el tipo de retorno de ambas sea entero.
        """
        self._scope = scope

        errors_before = len(errors)

        self.right.check_semantics(scope, errors)

        if errors_before == len(errors):
            if not self.right.has_return_value():
                message = 'Invalid use of binary logical operator with a ' \
                          'non-valued right expression at line {line}'
                errors.append(message.format(line=self.line_number))
            elif self.right.return_type != IntegerType():
                message = 'Invalid use of binary logical operator with a ' \
                          'non-integer right value at line {line}'
                errors.append(message.format(line=self.line_number))

        errors_before = len(errors)

        self.left.check_semantics(scope, errors)

        if errors_before == len(errors):
            if not self.left.has_return_value():
                message = 'Invalid use of binary logical operator with a ' \
                          'non-valued left expression at line {line}'
                errors.append(message.format(line=self.line_number))
            elif self.left.return_type != IntegerType():
                message = 'Invalid use of binary logical operator with a ' \
                          'non-integer left value at line {line}'
                errors.append(message.format(line=self.line_number))

        self._return_type = IntegerType()
예제 #8
0
 def check_semantics(self, scope, errors):
     """
     Para obtener información acerca de los parámetros recibidos por este 
     método consulte la documentación del método C{check_semantics} en la 
     clase C{LanguageNode}.
     
     El operador por realiza la multiplicación entre los el valor de la 
     expresión que se encuentra a la izquierda por el valor de la derecha.
     
     En la comprobación semántica de este nodo del árbol de sintáxis abstracta
     se comprueban semánticamente tanto la expresión de la izquierda como la 
     expresión de la derecha. Luego se comprueba que ambas retornen valor y 
     que el valor de retorno de ambas sea entero. 
     """
     self._scope = scope
     
     errors_before = len(errors)
     
     self.right.check_semantics(scope, errors)
     
     if errors_before == len(errors):
         if not self.right.has_return_value():
             message = 'Invalid use of times operator with a non-valued ' \
                       'right expression at line {line}'
             errors.append(message.format(line=self.line_number)) 
         elif self.right.return_type != IntegerType():
             message = 'Invalid use of times operator with a non-integer ' \
                       'right value at line {line}'
             errors.append(message.format(line=self.line_number))
     
     errors_before = len(errors)
     
     self.left.check_semantics(scope, errors)
     
     if errors_before == len(errors):
         if not self.left.has_return_value():
             message = 'Invalid use of times operator with a non-valued ' \
                       'left expression at line {line}'
             errors.append(message.format(line=self.line_number)) 
         elif self.left.return_type != IntegerType():
             message = 'Invalid use of times operator with a non-integer ' \
                       'left value at line {line}'
             errors.append(message.format(line=self.line_number))
         
     self._return_type = IntegerType()
예제 #9
0
 def check_semantics(self, scope, errors):
     """
     Para obtener información acerca de los parámetros recibidos por
     el método consulte la documentación del método C{check_semantics}
     en la clase C{LanguageNode}.
     
     Este nodo del árbol de sintáxis abstracta no requiere comprobación
     semántica, solamente se da valor al tipo de retorno del nodo que 
     siempre será C{IntegerType}.        
     """
     self._scope = scope
     self._return_type = IntegerType()
예제 #10
0
    def check_semantics(self, scope, errors):
        """
        Para obtener información acerca de los parámetros recibidos por
        el método consulte la documentación del método C{check_semantics}
        en la clase C{LanguageNode}.
             
        En la comprobación semántica de este nodo del árbol de sintáxis abstracta
        se crea un nuevo ámbito que contendrá la definicion de la variable de índice
        del ciclo como sólo lectura. Este ámbito tendrá como padre el ámbito donde
        fue definido el ciclo C{for}. 
        
        Luegoo, se comprueban semánticamente las expresiones correspondientes a los
        extremos inferiores y superiores del intervalo. Estas expresiones deben 
        tener valor de retorno entero. Además se comprueba semánticamente la 
        expresión que se ejecutará en cada iteración y esta se deja libre de 
        tener o no valor de retorno.
        """
        integer_type = IntegerType()

        self._scope = Scope(scope)
        self.scope.define_variable(self.index_name,
                                   VariableType(integer_type, True))

        errors_before = len(errors)

        self.lower_expression.check_semantics(self.scope, errors)

        if errors_before == len(errors):
            if not self.lower_expression.has_return_value():
                message = 'The expression for the lower bound of the for loop ' \
                          'at line {line} does not return a value'
                errors.append(message.format(line=self.line_number))
            elif self.lower_expression.return_type != integer_type:
                message = 'The return type of the expression for the lower bound ' \
                          'of the for loop at line {line} is not integer'
                errors.append(message.format(line=self.line_number))

        errors_before = len(errors)

        self.upper_expression.check_semantics(self.scope, errors)

        if errors_before == len(errors):
            if not self.upper_expression.has_return_value():
                message = 'The expression for the upper bound of the for loop ' \
                          'at line {line} does not return a value'
                errors.append(message.format(line=self.line_number))
            elif self.upper_expression.return_type != integer_type:
                message = 'The return type of the expression for the upper bound ' \
                          'of the for loop at line {line} is not integer'
                errors.append(message.format(line=self.line_number))

        self.expression.check_semantics(self.scope, errors)
예제 #11
0
    def generate_code(self, generator):
        """
        Genera el código correspondiente a la estructura del lenguaje Tiger
        representada por el nodo.

        Para obtener información acerca de los parámetros recibidos por
        este método consulte la documentación del método C{generate_code}
        de la clase C{LanguageNode}.
        """
        self.scope.generate_code(generator)
        int_code_type = IntegerType().code_type
        local_var = generator.define_local(int_code_type)
        generator.add_statement('{0} = {1};'.format(local_var, self.integer))
        self._code_name = local_var
예제 #12
0
 def check_semantics(self, scope, errors):
     """
     Para obtener información acerca de los parámetros recibidos por este método
     consulte la documentación del método C{check_semantics} en la clase 
     C{LanguageNode}.
     
     Los operadores cuyas clases del árbol de sintáxis abstracta derivan de esta
     deben recibir en ambos operandos expresiones con valor de retorno y el tipo
     de estas debe ser el mismo. Siempre tienen tipo de retorno entero (1 para 
     el resultado verdadero, 0 para el falso).
     
     En la comprobación semántica de este nodo del árbol de sintáxis abstracta
     se comprueban semánticamente tanto la expresión de la izquierda como la 
     expresión de la derecha. Luego se comprueba que ambas retornen valor y 
     que el tipo de retorno de ambas sea el mismo.
     """
     self._scope = scope
     
     errors_before = len(errors)
     
     self.right.check_semantics(scope, errors)
     
     if errors_before == len(errors):
         if not self.right.has_return_value():
             message = 'Invalid use of equality or inequality logical operator ' \
                       'with a non-valued right expression at line {line}'
             errors.append(message.format(line=self.line_number))
         
     self.left.check_semantics(scope, errors)
     
     if errors_before == len(errors):
         if not self.left.has_return_value():
             message = 'Invalid use of equality or inequality logical operator ' \
                       'with a non-valued left expression at line {line}'
             errors.append(message.format(line=self.line_number))
     
     if errors_before == len(errors):
         if self.right.return_type != self.left.return_type:
             # Check the special case of nil and records. nil can be assigned
             # to any record type, then r <> nil and r = nil are legal.
             valid_different_types = (RecordType, NilType)
             record_and_nil = (isinstance(self.right.return_type, valid_different_types) and 
                               isinstance(self.left.return_type, valid_different_types))
             if not record_and_nil:
                 message = 'Types of left and right operands of the equality or ' \
                           'inequality logical operator at line {line} does not match'
                 errors.append(message.format(line=self.line_number))
     
     self._return_type = IntegerType()
예제 #13
0
    def generate_code(self, generator):
        """
        Genera el código correspondiente a la estructura del lenguaje Tiger
        representada por el nodo.

        Para obtener información acerca de los parámetros recibidos por
        este método consulte la documentación del método C{generate_code}
        de la clase C{LanguageNode}.
        """
        self.scope.generate_code(generator)
        self.expression.generate_code(generator)
        local_var = generator.define_local(IntegerType().code_type)
        stmt = '{var} = -1 * {expr};'.format(var=local_var, expr=self.expression.code_name)
        generator.add_statement(stmt)
        self._code_name = local_var
예제 #14
0
    def _init_functions(self):
        """
        Inicializa las funciónes de la biblioteca standard del lenguaje Tiger
        definidas implícitamente el ámbito raíz.
        """
        int_type = IntegerType()
        string_type = StringType()

        print_type = FunctionType(None, [string_type], [''])
        print_type.code_name = 'tiger_print'
        printi_type = FunctionType(None, [int_type], [''])
        printi_type.code_name = 'tiger_printi'
        flush_type = FunctionType(None, [], [])
        flush_type.code_name = 'tiger_flush'
        getchar_type = FunctionType(string_type, [], [])
        getchar_type.code_name = 'tiger_getchar'
        ord_type = FunctionType(int_type, [string_type], [''])
        ord_type.code_name = 'tiger_ord'
        chr_type = FunctionType(string_type, [int_type], [''])
        chr_type.code_name = 'tiger_chr'
        size_type = FunctionType(int_type, [string_type], [''])
        size_type.code_name = 'tiger_size'
        substring_type = FunctionType(string_type,
                                      [string_type, int_type, int_type],
                                      ['', '', ''])
        substring_type.code_name = 'tiger_substring'
        concat_type = FunctionType(string_type, [string_type, string_type],
                                   ['', ''])
        concat_type.code_name = 'tiger_concat'
        not_type = FunctionType(int_type, [int_type], [''])
        not_type.code_name = 'tiger_not'
        exit_type = FunctionType(None, [int_type], [''])
        exit_type.code_name = 'tiger_exit'

        self._members['print'] = print_type
        self._members['printi'] = printi_type
        self._members['flush'] = flush_type
        self._members['getchar'] = getchar_type
        self._members['ord'] = ord_type
        self._members['chr'] = chr_type
        self._members['size'] = size_type
        self._members['substring'] = substring_type
        self._members['concat'] = concat_type
        self._members['not'] = not_type
        self._members['exit'] = exit_type
예제 #15
0
    def check_semantics(self, scope, errors):
        """
        Para obtener información acerca de los parámetros recibidos por
        el método consulte la documentación del método C{check_semantics}
        en la clase C{LanguageNode}.
        
        La estructura de acceso a array del lenguaje Tiger permite obtener
        el valor de un array en una posición determinada o asignarle un nuevo 
        valor a este array en la misma posición. Esta estructura recibe la 
        expresión que representa el acceso a la instancia de array y la 
        expresión correspondiente a la posición que se quiere acceder. 
        
        En la comprobación semántica de este nodo del árbol de sintáxis abstracta
        se verifica que la expresión que se correspondiente al array retorne
        valor y que este sea del tipo array, luego se comprueba que la 
        expresión de la posición retorne valor y que este sea de tipo entero. 
        
        En el proceso de comprobación semántica toman valor las propiedades
        C{return_type} y C{read_only}
        """
        self._scope = scope
        self.array.check_semantics(self.scope, errors)

        if self.array.has_return_value():
            array_type = self.array.return_type
            if isinstance(array_type, ArrayType):
                self._return_type = array_type.fields_types[0]
            else:
                self._return_type = None
                message = 'Invalid array access on a non array type at line {line}'
                errors.append(message.format(line=self.line_number))

            self.position.check_semantics(self.scope, errors)
            if not self.position.has_return_value():
                message = 'The expression for the position in the array does ' \
                          'not have a return value at line {line}'
                errors.append(message.format(line=self.line_number))
            elif self.position.return_type != IntegerType():
                message = 'Invalid non integer position for array access at line {line}'
                errors.append(message.format(line=self.line_number))
        else:
            message = 'Invalid array access on a non valued expression at line {line}'
            errors.append(message.format(line=self.line_number))
예제 #16
0
    def check_semantics(self, scope, errors):
        """
        Para obtener información acerca de los parámetros recibidos por
        el método consulte la documentación del método C{check_semantics}
        en la clase C{LanguageNode}.
        
        La expresión C{while-do} recibe una condición y una expresión, 
        de forma que evalua la condición y si esta es distinta de cero, 
        entonces la expresión es ejecutada.
        
        En la comprobación semántica de este nodo del árbol de sintáxis abstracta
        se comprueban semánticamente tanto la condición como la expresión contenidas
        en este. Luego se comprueba que la condición retorne valor, que el mismo sea 
        de tipo C{IntegerType} y que la expresión no retorne valor. Se reportarán
        errores semánticos si se encuentran errores durante la comprobación semántica
        de la condición o la expresión, si la condición no retorna valor, si este valor
        de retorno no es te tipo C{IntegerType} o si la expresión retorna algún valor.
        """
        self._scope = scope
        
        errors_before = len(errors)
        
        self.condition.check_semantics(scope, errors)
        
        if errors_before == len(errors):
            # The condition return type must be IntegerType
            if not self.condition.has_return_value():
                message = 'while used with a non-return condition at line {line}'
                errors.append(message.format(line=self.line_number))
            elif self.condition.return_type != IntegerType():
                message = 'Invalid type of condition of the while statement at line {line}'
                errors.append(message.format(line=self.line_number))

        errors_before = len(errors)
        
        self.expression.check_semantics(scope, errors)
        
        if errors_before == len(errors):
            # The expression must not return value
            if self.expression.has_return_value():
                message = 'while used with a expression with return value at line {line}'
                errors.append(message.format(line=self.line_number))
예제 #17
0
    def check_semantics(self, scope, errors):
        """
        Para obtener información acerca de los parámetros recibidos por
        el método consulte la documentación del método C{check_semantics}
        en la clase C{LanguageNode}.
        
        La expresión seguida de la instrucción C{if}, cuyo nodo del árbol de 
        sintáxis abstracta está almacenado en la propiedad C{condition}, deberá 
        tener valor de retorno entero. La expresión seguida de la instrucción
        C{then} no debe tener valor de retorno.
        
        En la comprobación semántica de este nodo del árbol de sintáxis abstracta 
        primeramente se comprueba que la expresión seguida de la instrucción C{if}
        esté correcta semánticamente, que tenga valor de retorno y que sea de tipo 
        C{IntegerType}. Luego se comprueba que la expresión seguida de la 
        instrucción C{then} esté correcta semánticamente y que no tenga valor 
        de retorno.
        """
        self._scope = scope

        # Check semantics of the condition expression.
        self.condition.check_semantics(scope, errors)
        if not self.condition.has_return_value():
            message = 'The condition of the if-then statement at line {line} ' \
                       'does not return a value'
            errors.append(message.format(line=self.line_number))
        elif self.condition.return_type != IntegerType():
            message = 'The condition of the if-then statement at line {line} ' \
                      'does not return an integer value'
            errors.append(message.format(line=self.line_number))

        # Check semantics of the then expression.
        self.then_expression.check_semantics(scope, errors)
        if self.then_expression.has_return_value():
            message = 'The then expression of the if-then statement ' \
                      'at line {line} should not return a value'
            errors.append(message.format(line=self.line_number))
 def check_semantics(self, scope, errors):
     """
     Para obtener información acerca del resto de los parámetros recibidos 
     por el método consulte la documentación del método C{check_semantics}
     en la clase C{LanguageNode}.
     
     La creación de una instancia de un tipo array recibe el nombre del
     tipo de array que se quiere crear, una expresión que corresponde a 
     la cantidad de elementos que va a tener el array y por último una 
     expresión que corresponde al valor con el que se inicializarán todos 
     los miembros de este nuevo array.
     
     En la comprobación semántica de este nodo del árbol de sintáxis abstracta
     se comprueba que el tipo array que se quiere crear ha sido definido en
     el ámbito correspondiente, se comprueba que la expresión correspondiente
     a la cantidad de elementos del array tenga valor de retorno y que este
     sea entero, por último se comprueba que la expresión correspondiente al
     valor que se le asignará a cada miembro de este nuevo array retorne
     tipo y que este sea igual al correspondiente a los valores en la 
     declaración del tipo de array.        
     """
     self._scope = scope
     
     errors_before = len(errors)
     
     try:
         self._return_type = self.scope.get_type_definition(self.type_name)
     except KeyError:
         message = 'Undefined type {type} at line {line}'
         errors.append(message.format(type=self._type_name, line=self.line_number))
         return
         
     if isinstance(self.return_type, ArrayType):
         
         self.count.check_semantics(self.scope, errors)
         if errors_before != len(errors):
             return            
         
         if not self.count.has_return_value():
             message = 'Non value expression for the array length at line {line}'
             errors.append(message.format(line=self.line_number))
             return
         elif self.count.return_type != IntegerType():
             message = 'Non integer expression for the array length at line {line}'
             errors.append(message.format(line=self.line_number))
             return
             
         self.value.check_semantics(self.scope, errors)
         if errors_before != len(errors):
             return
                     
         if not self.value.has_return_value():
             message = 'Non valued expression for the array value at line {line}'
             errors.append(message.format(line=self.line_number))
         elif self.value.return_type == NilType():
             if not isinstance(self.return_type.fields_types[0], RecordType):
                 message = 'Invalid nil value for the array value at line {line}'
                 errors.append(message.format(line=self.line_number))
         elif self.value.return_type != self.return_type.fields_types[0]:
             message = 'Incompatible type for the array value at line {line}'
             errors.append(message.format(line=self.line_number))
     else:
         message = 'Invalid non array type {type_name} at line {line}'
         errors.append(message.format(type_name = self._type_name, 
                                      line=self.line_number))
예제 #19
0
    def check_semantics(self, scope, errors):
        """
        Para obtener información acerca de los parámetros recibidos por
        el método consulte la documentación del método C{check_semantics}
        en la clase C{LanguageNode}.
        
        La expresión seguida de la instrucción C{if}, cuyo nodo del árbol de 
        sintáxis abstracta está almacenado en la propiedad C{condition}, deberá 
        tener valor de retorno entero. Las expresiones seguidas de las 
        instrucciones C{then} y C{else} deben tener el mismo tipo de retorno
        o no tener valor de retorno ambas. El tipo del valor de retorno de la 
        expresión C{if-then-else} será el mismo que el de estas expresiones o
        no retornará valor si estas no lo hacen. 
        
        En la comprobación semántica de este nodo del árbol de sintáxis abstracta 
        primeramente se comprueba que la expresión seguida de la instrucción C{if}
        esté correcta semánticamente, que tenga valor de retorno y que sea de tipo 
        C{IntegerType}. Luego, se comprueba que las expresiones seguidas de las 
        instrucciones C{then} y C{else} estén correctas semánticamente y que el 
        tipo de su valor de retorno sea el mismo o ambas no tengan valor de retorno.
        Para finalizar especifica el tipo de retorno que tendrá la expresión, 
        el cual coincidirá con el tipo de las expresiones.
        """
        self._scope = scope

        # Check semantics of the condition expression.
        self.condition.check_semantics(scope, errors)
        if not self.condition.has_return_value():
            message = 'The condition of the if-then-else statement at line {line} ' \
                       'does not return a value'
            errors.append(message.format(line=self.line_number))
        elif self.condition.return_type != IntegerType():
            message = 'The condition of the if-then-else statement at line {line} ' \
                      'does not return an integer value'
            errors.append(message.format(line=self.line_number))

        # Check semantics of the then and else expressions.
        errors_before = len(errors)

        self.then_expression.check_semantics(scope, errors)
        self.else_expression.check_semantics(scope, errors)

        if errors_before == len(errors):
            then_returns = self.then_expression.has_return_value()
            else_returns = self.else_expression.has_return_value()
            if then_returns and else_returns:
                if self.then_expression.return_type != self.else_expression.return_type:
                    # Check the special case of nil and records.
                    valid_different_types = (RecordType, NilType)
                    record_and_nil = (
                        isinstance(self.then_expression.return_type,
                                   valid_different_types)
                        and isinstance(self.else_expression.return_type,
                                       valid_different_types))
                    if not record_and_nil:
                        message = 'The return type of the expressions of the if-then-else ' \
                                  'statement at line {line} is not the same'
                        errors.append(message.format(line=self.line_number))
            elif then_returns or else_returns:
                message = 'One of the expressions of the if-then-else statement at ' \
                          'line {line} returns but the other does not'
                errors.append(message.format(line=self.line_number))

            # Set the return type of the expression (if any).
            if then_returns and else_returns:
                self._return_type = self.then_expression.return_type