Beispiel #1
0
        public override void CheckSemantic(Scope scope, IList<Error> errors)
        {
            //El 'for' define un nuevo scope
            Scope = new Scope(scope);
            //Anadimos una variable de tipo entero de solo lectura al scope del 'for'
            Scope.Add(VariableName, IntegerType.Create(), true);

            //Evaluamos la expresion de inicio y la de fin.
            //OJO: Con el Scope que veniamos usando hasta ahora, pues la variable del 'for' no es visible para estas expresiones
            int errorsCount = errors.Count;
            ExpressionInitial.CheckSemantic(scope, errors);
            ExpressionFinal.CheckSemantic(scope, errors);
            //Si ocurrio algun error, lo mas probable es que no se haya asignado un tipo de retorno a estas expresiones, por lo que terminamos
            if (errorsCount != errors.Count) {
                return;
            }

            //Comprobamos que retornen valores las expresiones anteriores y que sea entero
            ErrorsHelper.CheckIfReturnTypeIsInt(ExpressionInitial, errors, "The expression that defines the first value in the 'for' must return a value", "The expression that defines the first value in the 'for' must return an integer");
            ErrorsHelper.CheckIfReturnTypeIsInt(ExpressionFinal, errors, "The expression that defines the last value in the 'for' must return a value", "The expression that defines the last value in the 'for' must return an integer");

            //Comprobamos el cuerpo
            Body.CheckSemantic(Scope, errors);

            //Comprobamos que retorne algun valor
            if (Body.ReturnsValue()) {
                errors.Add(new MessageError(Line, Column, "Expression body of 'for' must not return a value"));
            }
        }
Beispiel #2
0
        public override void CheckSemantic(Scope scope, IList<Error> errors)
        {
            //Comprobamos que lo de la izquierda sea un record
            //Luego que exista el campo al que estamos accediendo
            int errorsCount = errors.Count;
            //Chequeamos semanticamente la expresion a la que estamos accediendo
            Left.CheckSemantic(scope, errors);
            if (errorsCount != errors.Count) {
                return;
            }

            //Si no retorna valor la expresion
            ErrorsHelper.CheckIfReturnsValue(Left, errors, "The expression being accessed must return a value");
            if (errorsCount != errors.Count) {
                return;
            }

            //Si no es un record
            if (!(Left.ReturnType is RecordType)) {
                errors.Add(new UnexpectedTypeError(Line, Column, Left.ReturnType, "record"));
                return;
            }

            //Si es un record, comprobamos que exista ese campo...
            var record = (RecordType) Left.ReturnType;
            if (!record.Fields.ContainsKey(FieldName))
            {
                errors.Add(new FieldNotFoundError(Line, Column, record.Name, FieldName));
            }
            else {
                //El tipo de retorno sera el mismo que el del campo del record
                ReturnType = record.Fields[FieldName];
            }
        }
        /// <summary>
        /// Chequea semanticamente el cuerpo de la funcion
        /// Ademas, comprueba que el tipo de retorno especificado coincide con el del cuerpo de la funcion
        /// </summary>
        /// <param name="scope"></param>
        /// <param name="errors"></param>
        public void CheckBodySemantic(Scope scope, IList<Error> errors)
        {
            int errorsCount = errors.Count;
            Body.CheckSemantic(Scope, errors);

            //Si ocurrio algun error...
            if (errorsCount != errors.Count) {
                return;
            }

            //Comprobamos que el tipo de retorno especificado coincida con el del cuerpo de la funcion
            if (Type != null)
            {
                var type = scope.GetType(Type);

                //Si la expresion no retorna ningun valor
                if (!Body.ReturnsValue())
                {
                    errors.Add(new NonValueAssignmentError(Line, Column, Name));
                }
                //Comprobamos que el tipo del cuerpo de la funcion sea igual al especificado
                else if (type != Body.ReturnType)
                {
                    //Si no pasa que el tipo es 'nil' y puede ser asignado (es decir, si el tipo no es 'nil', o si el tipo es 'nil' y no puede ser asignado
                    if (!(Body.ReturnType is NilType && NilType.CanBeAssignedTo(type))) {
                        errors.Add(new UnexpectedTypeError(Line, Column, type, Body.ReturnType));
                    }
                }
                //TODO: Es posible retornar Nil aqui?
            }
        }
Beispiel #4
0
        public override void CheckSemantic(Scope scope, IList<Error> errors)
        {
            //ReturnType = Else.ReturnType
            Condition.CheckSemantic(scope, errors);
            //Comprobamos que Condition retorne un entero
            ErrorsHelper.CheckIfReturnTypeIsInt(Condition, errors, "The condition must return a value", "The condition must return an integer");

            int errorsCount = errors.Count;
            ThenBody.CheckSemantic(scope, errors);

            if (errorsCount != errors.Count) {
                return;
            }

            //Si no existe Else...
            if (ElseBody == null) {
                //Si retorna valor...
                if (ThenBody.ReturnsValue()) {
                    errors.Add(new MessageError(Line, Column, "'then' expression must not return a value"));
                }
            }
            //Si existe el else...
            else {
                //Ambas expresiones deben, o retornar el mismo tipo, o no retornar valor
                ElseBody.CheckSemantic(scope, errors);

                //Comprobamos si ambos no retornan tipo
                if (!ThenBody.ReturnsValue() && !ElseBody.ReturnsValue())
                {
                    //Entonces esta expresion no retorna nada
                    ReturnType = null;
                    return;
                }
                //Si retornan tipos diferentes...
                if (ThenBody.ReturnType != ElseBody.ReturnType)
                {
                    //Si alguno de los dos es nil...
                    if (ThenBody.ReturnType is NilType || ElseBody.ReturnType is NilType)
                    {
                        var nonNilType = ThenBody.ReturnType is NilType ? ElseBody.ReturnType : ThenBody.ReturnType;
                        //Si no pasa que el tipo es 'nil' y puede ser asignado (es decir, si el tipo no es 'nil', o si el tipo es 'nil' y no puede ser asignado)
                        if (!(NilType.CanBeAssignedTo(nonNilType)))
                        {
                            errors.Add(new MessageError(Line, Column,
                                                        "In if-then-else expressions, both 'then' and 'else' expressions must either return no value or be of the same type"));
                        }
                    }
                    else {
                        errors.Add(new MessageError(Line, Column,
                                                    "In if-then-else expressions, both 'then' and 'else' expressions must either return no value or be of the same type"));
                    }

                }
                //Si retornan el mismo tipo
                else {
                    ReturnType = ThenBody.ReturnType;
                }
            }
        }
Beispiel #5
0
 private void AddStringVariable(string name, Scope s = null)
 {
     if (s == null)
         _scope.Add(name, StringType.Create());
     else {
         s.Add(name, StringType.Create());
     }
 }
Beispiel #6
0
        public void CheckExistence_OneTypeInParent_TwoScopes()
        {
            var s = new Scope();
            s.Add(StringType.Create());
            _scope = new Scope(s);

            Assert.That(_scope.ExistsType("string"));
            Assert.That(!_scope.ExistsType("string", false));
        }
Beispiel #7
0
        public void CheckExistence_OneVariableInParent_TwoScopes()
        {
            var s = new Scope();
            AddStringVariable("x", s);
            _scope = new Scope(s);

            Assert.That(_scope.ExistsVariableOrCallable("x"));
            Assert.That(!_scope.ExistsVariableOrCallable("x", false));
        }
Beispiel #8
0
        public void Two_Scopes()
        {
            var s = new Scope();
            s.Add("x", StringType.Create());
            Scope.Parent = s;
            var ast = Utils.BuildAST(@"let var x := 10 in x + 2 end");
            ast.CheckSemantic(Scope, Errors);

            Assert.That(Errors.Count == 0);
            Assert.That(ast.ReturnType is IntegerType);
        }
Beispiel #9
0
        public Scope(Scope parent)
        {
            DefinedTypes = new Dictionary<string, TigerType>();
            DefinedVariables = new Dictionary<string, Variable>();
            DefinedCallables = new Dictionary<string, Callable>();
            Parent = parent;

            InvalidCallableNames = new List<string>();
            //TODO: Eliminar, y subirlo para el scope padre
            InvalidTypeNames = new List<string> {"string", "int"};
        }
        public override void CheckSemantic(Scope scope, IList<Error> errors)
        {
            //Chequeamos la semantica del cuerpo de la asignacion
            //Otro nodo se encargara de comprobar que el nombre del campo sea correcto, el tipo, etc
            Body.CheckSemantic(scope, errors);

            ErrorsHelper.CheckIfReturnsValue(Body, errors,
                                                 string.Format(
                                                     "The expression to be assigned to the field '{0}' must return a value",
                                                     FieldName));
            ReturnType = Body.ReturnType;
        }
Beispiel #11
0
 public override void CheckSemantic(Scope scope, IList<Error> errors)
 {
     Scope = scope;
     //Comprobamos que exista la variable con ese nombre en el scope
     if (!scope.ExistsVariable(Name))
     {
         errors.Add(new UndefinedVariableError(Line, Column, Name));
     }
     else {
         var variable = scope.GetVariable(Name);
         //Asignamos el tipo de retorno
         ReturnType = variable.Type;
     }
 }
Beispiel #12
0
        public void AlreadyExistingType_ButInOuterScope()
        {
            var s = new Scope();
            s.Add(new RecordType("someRecord", new Fields()));
            Scope.Parent = s;

            var ast = (LetInEndNode)Utils.BuildAST("let type someRecord = array of string in end");
            ast.CheckSemantic(Scope, Errors);
            Assert.That(Errors.Count == 0);
            Assert.That(ast.Scope.ExistsType("someRecord"));
            Assert.That(ast.Scope.GetType("someRecord") is ArrayType);
            var type = (ArrayType)ast.Scope.GetType("someRecord");
            Assert.That(type.ElementsType is StringType);
        }
        public override void CheckSemantic(Scope scope, IList<Error> errors)
        {
            //Chequeamos la semantica del cuerpo
            int errorsCount = errors.Count;
            Body.CheckSemantic(scope, errors);
            if (errorsCount != errors.Count) {
                return;
            }

            //Comprobamos que la expresion retorne algun valor, y que sea entero
            ErrorsHelper.CheckIfReturnTypeIsInt(Body, errors);

            //El tipo de retorno de esta expresion es entero
            ReturnType = IntegerType.Create();
        }
        public override void CheckSemantic(Scope scope, IList<Error> errors)
        {
            //Si no hay expresiones, no se hace nada. El tipo de retorno sigue siendo Null
            if (Sequence.Count == 0) {
                return;
            }

            //Chequeamos semanticamente cada expresion
            foreach (var expr in Sequence) {
                expr.CheckSemantic(scope, errors);
            }

            //El tipo de retorno sera el de la ultima expresion
            ReturnType = Sequence[Sequence.Count - 1].ReturnType;
        }
Beispiel #15
0
        /// <summary>
        /// Chequea que ambos operandos sean enteros y que retornen valor
        /// Importante: Los nodos que difieran en el chequeo semantico, deben sobreescribirlo
        /// </summary>
        /// <param name="scope"></param>
        /// <param name="errors"></param>
        public override void CheckSemantic(Scope scope, IList<Error> errors)
        {
            //Se comprueban ambos nodos (izquierda y derecha)
            int errorsCount = errors.Count;
            Left.CheckSemantic(scope, errors);
            Right.CheckSemantic(scope, errors);

            //Si ocurrio algun error
            if (errorsCount != errors.Count) {
                return;
            }

            //Comprobamos que ambas expresiones retornan valor
            ErrorsHelper.CheckIfReturnsValue(Left, errors, GetNoValueMessage("Left"));
            ErrorsHelper.CheckIfReturnsValue(Right, errors, GetNoValueMessage("Right"));

            if (errorsCount != errors.Count) {
                return;
            }

            //Comprobamos que ambas expresiones sean del tipo permitido por este nodo
            CheckIfAreTypesAllowed(errors);

            if (errorsCount != errors.Count) {
                return;
            }

            //Chequeamos que ambas expresiones retornen el mismo tipo (en Tiger)
            if (Left.ReturnType != Right.ReturnType) {
                //Si no retornan el mismo tipo, pero si un tipo es nil
                if (Left.ReturnType is NilType || Right.ReturnType is NilType) {
                    //Comprobamos que el otro tipo sea 'compatible' con nil
                    var nonNilType = Left.ReturnType is NilType ? Right.ReturnType : Left.ReturnType;
                    if (!NilType.CanBeAssignedTo(nonNilType)) {
                        errors.Add(new OperatorError(Line, Column, OperatorName, Left.ReturnType, Right.ReturnType));
                    }
                }
                else {
                    errors.Add(new OperatorError(Line, Column, OperatorName, Left.ReturnType, Right.ReturnType));
                }
            }
            //Si ambos tipos son nil
            else if (Left.ReturnType is NilType && Right.ReturnType is NilType) {
                errors.Add(new MessageError(Line, Column, "The type of the two expressions cannot be inferred because 'nil' was used"));
            }
            //El tipo de retorno de esta expresion sera entero
            ReturnType = IntegerType.Create();
        }
Beispiel #16
0
        public override void CheckSemantic(Scope scope, IList<Error> errors)
        {
            //Comprobando que exista el record
            if (!scope.ExistsType(Name))
            {
                errors.Add(new UndefinedTypeError(Line, Column, Name));
                return;
            }

            var type = scope.GetType(Name);
            var array = type as ArrayType;

            //Si el tipo que obtuvimos no es un record...
            if (array == null)
            {
                errors.Add(new UnexpectedTypeError(Line, Column, type, Name));
                return;
            }

            //El tipo de retorno sera el de la definicion del array
            ReturnType = array;

            int errorsCount = errors.Count;
            Count.CheckSemantic(scope, errors);
            //Si hubo errores
            if (errorsCount != errors.Count) {
                return;
            }

            //Si la expresion que da la cantidad de elementos del array no es entera
            ErrorsHelper.CheckIfReturnTypeIsInt(Count, errors, string.Format("The size expression of the array '{0}' must return a value", Name), string.Format("The size expression of the array '{0}' must be an integer", Name));

            errorsCount = errors.Count;
            InitialValue.CheckSemantic(scope, errors);
            if (errorsCount != errors.Count) {
                return;
            }

            //Que el tipo de InitialValue sea igual al tipo definido en el array
            if (array.ElementsType != InitialValue.ReturnType) {
                //Si no pasa que el tipo es 'nil' y puede ser asignado (es decir, si el tipo no es 'nil', o si el tipo es 'nil' y no puede ser asignado
                if (!(InitialValue.ReturnType is NilType && NilType.CanBeAssignedTo(array.ElementsType))) {
                    errors.Add(new UnexpectedTypeError(Line, Column, InitialValue.ReturnType, array.ElementsType));
                }
            }
        }
        public override void CheckSemantic(Scope scope, IList<Error> errors)
        {
            int errorsCount = errors.Count;

            //Chequear que el tipo que almacenara el array exista en el scope
            if (!scope.ExistsType(TypeName)) {
                errors.Add(new UndefinedTypeError(Line, Column, TypeName));
            }

            //Si ocurrio algun error
            if (errorsCount != errors.Count) {
                return;
            }

            //Anadimos el nuevo tipo definido al scope
            scope.Add(new ArrayType(Name, scope.GetType(TypeName)), updateIfExists: true);
        }
Beispiel #18
0
        public override void CheckSemantic(Scope scope, IList<Error> errors)
        {
            //La condicion debe retornar entero
            //El cuerpo no puede retornar valor
            //No retorna nada

            int errorsCount = errors.Count;
            Condition.CheckSemantic(scope, errors);
            Body.CheckSemantic(scope, errors);

            //La condicion debe retornar un entero
            ErrorsHelper.CheckIfReturnTypeIsInt(Condition, errors, "The condition must return a value", "The condition must return an integer");

            //El cuerpo no puede retornar valor
            if (Body.ReturnsValue()) {
                errors.Add(new MessageError(Line, Column, "Expression body of 'while' must not return a value"));
            }
        }
Beispiel #19
0
        public override void CheckSemantic(Scope scope, IList<Error> errors)
        {
            //Comprobamos que lo de la izquierda sea un record
            //Luego que exista el campo al que estamos accediendo
            int errorsCount = errors.Count;
            //Chequeamos semanticamente la expresion a la que estamos accediendo
            Left.CheckSemantic(scope, errors);

            if (errorsCount != errors.Count)
            {
                return;
            }

            //Chequeamos que el indice sea entero
            Index.CheckSemantic(scope, errors);
            ErrorsHelper.CheckIfReturnsValue(Index, errors, "The index expression must return a value");

            if (!(Index.ReturnType is IntegerType)) {
                errors.Add(new UnexpectedTypeError(Line, Column, Index.ReturnType, "int"));
            }

            if (errorsCount != errors.Count) {
                return;
            }

            //Si no retorna valor la expresion
            ErrorsHelper.CheckIfReturnsValue(Left, errors, "The expression being accessed must return a value");
            if (errorsCount != errors.Count)
            {
                return;
            }

            //Si no es un record
            if (!(Left.ReturnType is ArrayType))
            {
                errors.Add(new UnexpectedTypeError(Line, Column, Left.ReturnType, "record"));
                return;
            }

            //Si es un record, comprobamos que exista ese campo...
            var array = (ArrayType)Left.ReturnType;
            //El tipo de retorno, sera el tipo de retorno de los elementos que almacena el array
            ReturnType = array.ElementsType;
        }
Beispiel #20
0
        public override void CheckSemantic(Scope scope, IList<Error> errors)
        {
            int errorsCount = errors.Count;
            //Comprobamos que este correctamente Left
            Left.CheckSemantic(scope, errors);
            //Comprobamos que este correctamente Body
            Body.CheckSemantic(scope, errors);

            //Si ocurrio algun error, paramos
            if (errorsCount != errors.Count) {
                return;
            }

            //Comprobamos que ambas expresiones retornen valor...
            ErrorsHelper.CheckIfReturnsValue(Left, errors,
                                             "The expression that is being assigned a value must return a value");
            ErrorsHelper.CheckIfReturnsValue(Body, errors,
                                 "The expression to be assigned must return a value");
            if (errorsCount != errors.Count) {
                return;
            }

            //Si 'Left' es una variable, y es de solo lectura => Error!
            if (Left is VariableAccessNode) {
                var varAccessNode = (VariableAccessNode) Left;
                //Buscamos la variable a la que estamos accediendo en el scope
                var variable = scope.GetVariable(varAccessNode.Name);
                if (variable.ReadOnly) {
                    errors.Add(new MessageError(Line, Column, string.Format("Cannot assign value to read-only variable '{0}'", variable.Name)));
                }
            }

            //Si el tipo de retorno es diferente
            if (Body.ReturnType != Left.ReturnType) {
                //Si se esta asignando nil, comprobar que el tipo lo permita
                if (!(Body.ReturnType is NilType) || !NilType.CanBeAssignedTo(Left.ReturnType))
                {
                    errors.Add(new UnexpectedTypeError(Line, Column, Body.ReturnType, Left.ReturnType));
                }
            }

            //Esta expresion no retorna valor
        }
Beispiel #21
0
        public override void CheckSemantic(Scope scope, IList<Error> errors)
        {
            //Comprobamos que la funcion exista
            if (!scope.ExistsCallable(Name)) {
                errors.Add(new UndefinedFunctionError(Line, Column, Name));
                return;
            }

            //Obtenemos la funcion que llamaremos
            var callable = scope.GetCallable(Name);

            if (callable.Fields.Count != Parameters.Count) {
                errors.Add(new MessageError(Line, Column, "The arguments of the call do not match the parameters of the defined function"));
                //Para poder continuar el chequeo semantico y detectar mas errores en el programa...
                AssignReturnType(scope, callable);
                return;
            }

            for (int i = 0; i < Parameters.Count; i++) {
                var parameter = Parameters[i];
                var field = callable.Fields[i];

                //Chequeamos la semantica del argumento
                parameter.CheckSemantic(scope, errors);

                ErrorsHelper.CheckIfReturnsValue(parameter, errors, string.Format("The argument '{0}' must return a value", i));
                if (parameter.ReturnsValue()) {
                    //Comprobamos que el tipo de retorno coincida con la definicion de la funcion
                    var definedType = scope.GetType(field.TypeId);
                    var returnType = parameter.ReturnType;

                    //Si el tipo de retorno es diferente...
                    if (definedType != returnType) {
                        errors.Add(new MessageError(Line, Column, string.Format("Argument '{0}' is not assignable to parameter type '{1}'", returnType, definedType)));
                    }
                }
            }

            //El tipo de retorno es el tipo de retorno de la funcion al definirse (si es funcion)
            AssignReturnType(scope, callable);
        }
Beispiel #22
0
        public override void CheckSemantic(Scope scope, IList<Error> errors)
        {
            IList<ExpressionNode> ancestors = new List<ExpressionNode>();
            var parent = Parent;

            bool found = false;

            while (parent != null) {
                //Vamos guardando el camino...
                ancestors.Add(parent);

                //Si encontramos a un ciclo, paramos
                if (parent is LoopNode) {
                    found = true;
                    break;
                }

                //Si encontramos una declaracion de funcion/procedimiento, sin haber encontrado un ciclo, no es valido...
                if (parent is CallableDeclarationNode) {
                    var dec = (CallableDeclarationNode) parent;
                    errors.Add(new MessageError(Line, Column, string.Format("'break' expression is inside inside the function/procedure '{0}'", dec.Name)));
                    return;
                }

                parent = parent.Parent;
            }

            //Si llegamos al nodo raiz y no encontramos un ciclo...
            if (!found) {
                errors.Add(new MessageError(Line, Column, string.Format("'break' expression must be inside either a 'while' or 'for' expression")));
                return;
            }

            //Marcamos todos los nodos del camino como 'rompibles'
            foreach (var expr in ancestors) {
                expr.IsBreakable = true;
            }
        }
        public override void CheckSemantic(Scope scope, IList<Error> errors)
        {
            //Comprobar que no haya sido definido este tipo en este mismo scope
            //Comprobar que no haya dos campos con un mismo nombre
            //Comprobar que todos los tipos de los campos esten definidos

            int errorsCount = errors.Count;

            IDictionary<string, TigerType> fields = new Dictionary<string, TigerType>();

            foreach (var field in Fields) {
                bool errorInField = false;
                //Comprobando que el tipo de este campo este definido
                if (!scope.ExistsType(field.TypeId)) {
                    errors.Add(new UndefinedTypeError(Line, Column, field.TypeId));
                    errorInField = true;
                }
                //Comprobando que no exista ya un campo con este nombre
                if (fields.ContainsKey(field.Id))
                {
                    errors.Add(new DuplicateFieldError(Line, Column, field.Id));
                    errorInField = true;
                }
                if (!errorInField) {
                    fields.Add(field.Id, scope.GetType(field.TypeId));
                }
            }

            //Si ocurrio un error
            if (errorsCount != errors.Count) {
                return;
            }

            //Si no ocurrio ningun error, actualizamos la definicion de este tipo
            //Guardamos el record en este nodo para usarlo en la generacion de codigo
            RecordType = new RecordType(Name, new Fields(fields));
            scope.Add(RecordType, updateIfExists: true);
        }
        public override void CheckSemantic(Scope scope, IList<Error> errors)
        {
            //Comprobamos que no exista una variable/funcion en este mismo scope definida
            if (scope.ExistsVariableOrCallable(Name, false) || scope.IsCallableNameInvalid(Name)) {
                errors.Add(new AlreadyDefinedError(Line, Column, Name));
                return;
            }

            int errorsCount = errors.Count;
            IList<string> parameters = new List<string>();
            //Creamos el scope de la nueva funcion
            Scope = new Scope(scope);

            //Chequeamos los parametros...
            foreach (var field in Fields) {
                bool errorInField = false;
                //Comprobar que el tipo exista
                if (!scope.ExistsType(field.TypeId)) {
                    errors.Add(new UndefinedTypeError(Line, Column, field.TypeId));
                    errorInField = true;
                }
                //Si existe un parametro con ese mismo nombre
                if (parameters.Contains(field.Id))
                {
                    errors.Add(new DuplicateParameterError(Line, Column, field.Id));
                    errorInField = true;
                }
                else {
                    parameters.Add(field.Id);
                }

                //Anadimos este parametro al scope de la funcion
                if (!errorInField) {
                    Scope.Add(field.Id, scope.GetType(field.TypeId));
                }
            }

            //Si me especificaron un tipo y este no existe
            if (Type != null && !scope.ExistsType(Type)) {
                errors.Add(new UndefinedTypeError(Line, Column, Type));
            }

            //Si hubo errores en los parametros no seguimos o en la definicion explicita del tipo de la funcion...
            if (errorsCount != errors.Count) {
                return;
            }

            //Si estamos aqui es porque no hubo ningun error anteriormente

            //OJO: No chequeamos la semantica del cuerpo de la funcion. Lo haremos en una segunda pasada

            //Si no hubo ningun problema...
            if (errorsCount == errors.Count) {
                Callable = new Callable(Name, Fields, Type);
                scope.AddCallable(Callable);
            }
        }
Beispiel #25
0
 public void Init()
 {
     _scope = new Scope();
 }
Beispiel #26
0
 private void ProcessVariableDeclarations(IList<DeclarationNode> group, Scope scope, IList<Error> errors)
 {
     //Las variables no necesitan un trato especial
     foreach (var dec in @group) {
         dec.CheckSemantic(scope, errors);
     }
 }
Beispiel #27
0
        private void ProcessTypeDeclarations(IList<DeclarationNode> groupOfDeclarations, Scope scope,
                                             IList<Error> errors)
        {
            int errorsCount = 0;

            //Anadimos los encabezados de las declaraciones de los tipos
            //Y a la vez, comprobamos que no exista un tipo con ese nombre (en este scope solamente)
            foreach (var dec in groupOfDeclarations) {
                if (scope.ExistsType(dec.Name, false) || scope.IsTypeNameInvalid(dec.Name)) {
                    errors.Add(new AlreadyDefinedError(dec.Line, dec.Column, dec.Name));
                    break;
                }
                scope.Add(null, dec.Name);
            }

            //Si ocurrio algun error, paramos
            if (errorsCount != errors.Count) {
                return;
            }

            //Separamos los alias y las declaraciones de array/records..

            //Listado de declaraciones que no son alias
            var notAliasDeclarations = groupOfDeclarations.Where(x => !(x is AliasDeclarationNode)).ToList();
            //Listadoo de declaraciones que son alias
            var aliasDeclarations = groupOfDeclarations.OfType<AliasDeclarationNode>().ToList();

            /* Procesamos los alias primero, y obtenemos varios conjuntos de alias
             * En un mismo conjunto estaran los alias que hacen referencia entre ellos
             * El primer elemento del conjunto sera el alias por el que se empezo a analizar
             * El ultimo elemento sera el que desembocó en un tipo existente/valido
             *
             * Ejemplo:
             *
             * type r = {x : a}
             * type a = b
             * type c = r
             * type b = c
             *
             * Aqui obtendremos un solo conjunto con las declaraciones: {a = b} {b = c} {c = r}
            */
            IList<List<AliasDeclarationNode>> aliasesGroups = ProcessAliasesGroup(aliasDeclarations, scope, errors);

            //Si ocurrio algun error, paramos
            if (errorsCount != errors.Count) {
                return;
            }

            //Chequeamos semanticamente cada tipo (que no sea alias)
            //Todos los tipos posibles a los que pueden hacer referencia han sido anadidos al scope
            foreach (var declaration in notAliasDeclarations) {
                declaration.CheckSemantic(scope, errors);
            }

            //Si hubo algun error
            if (errorsCount != errors.Count) {
                return;
            }

            //Por cada grupo de alias, vamos de atras hacia delante resolviendo los tipos
            //Pues el ultimo en cada grupo es el que apuntaba hacia un tipo valido (y no hacia otro alias)
            foreach (var aliasGroup in aliasesGroups) {
                for (int i = aliasGroup.Count - 1; i >= 0; i--) {
                    var alias = aliasGroup[i];
                    //Actualizamos la definicion del tipo en el scope
                    alias.UpdateDefinition(scope);
                }
            }

            //Actualizamos las declaraciones de los no-alias
            foreach (var declaration in notAliasDeclarations) {
                var t = (TypeDeclarationNode) declaration;
                //Actualizamos la definicion del tipo en el scope
                t.UpdateDefinition(scope);
            }
        }
Beispiel #28
0
        private void ProcessCallableDeclarations(IList<DeclarationNode> group, Scope scope, IList<Error> errors)
        {
            //Por cada procedimiento o funcion en el bloque...
            int errorsCount = errors.Count;
            foreach (CallableDeclarationNode c in group) {
                //Chequeamos la semantica de la funcion.
                //OJO: No chequea la semantica del cuerpo de la funcion
                c.CheckSemantic(scope, errors);
                //Si ocurrio algun error chequeando la semantica de la funcion (en la 1ra pasada)
                if (errorsCount != errors.Count) {
                    return;
                }
            }

            //Hacemos una segunda pasada para chequear los cuerpos de las funciones (una vez ya definidas formalmente todas las funciones del bloque)
            //Y ver que el tipo de retorno de la funcion sea igual al especificado
            foreach (CallableDeclarationNode c in group) {
                errorsCount = errors.Count;
                c.CheckBodySemantic(scope, errors);

                //Si hubo algun error, eliminamos esa funcion del scope. TODO: Necesario?
                if (errorsCount != errors.Count) {
                    scope.DefinedCallables.Remove(c.Name);
                }
            }
        }
Beispiel #29
0
        /// <summary>
        /// Encargado de recibir un conjunto de declaraciones de tipo alias (pertenecientes a un mismo bloque)
        /// y chequear que no haya ciclos, etc.
        /// </summary>
        /// <param name="aliasDeclarations">Conjunto de alias</param>
        /// <param name="scope"></param>
        /// <param name="errors"></param>
        /// <returns>Varios conjunticos de alias donde en cada conjunto estan los relacionados. Ademas, estan en el orden que se fueron resolviendo</returns>
        private IList<List<AliasDeclarationNode>> ProcessAliasesGroup(IList<AliasDeclarationNode> aliasDeclarations,
                                                                      Scope scope, IList<Error> errors)
        {
            //Donde guardaremos los conjunticos
            var result = new List<List<AliasDeclarationNode>>();

            //Si no hay ningun Alias declaration
            if (aliasDeclarations.Count == 0) {
                return result;
            }

            //Creamos el primer conjunto
            result.Add(new List<AliasDeclarationNode>());

            //Convertimos los alias a un diccionario (para facilitar el manejo) de la forma:
            //{ Name : AliasDeclarationNode }
            var dictAliases = aliasDeclarations.ToDictionary(x => x.Name, x => x);

            //Cogemos el primer alias
            AliasDeclarationNode alias = aliasDeclarations[0];

            //Mientras queden alias por analizar
            while (dictAliases.Count > 0) {
                //Tipo al que apunta
                var type = alias.AliasType;

                //Si no existe el tipo, paramos
                if (!scope.ExistsType(type)) {
                    errors.Add(new UndefinedTypeError(Line, Column, type));
                    break;
                }

                //Si el tipo ya ha sido definido correctamente o si no ha sido definido completamente pero no apunta a ningun alias (ej. apunta a un record que esta por definirse)
                if (IsFullyDefined(type, scope) || DoesNotPointToAlias(type, aliasDeclarations)) {
                    //Cogemos el tipo al que apunta
                    var t = scope.GetType(type);
                    //Anadimos este alias diciendo que apunta a aquel tipo
                    scope.Add(t, alias.Name, updateIfExists: true);
                    //Anadimos el alias al grupo actual
                    result[result.Count - 1].Add(alias);
                    //Lo eliminamos de los procesados (ya acabamos con el)
                    dictAliases.Remove(alias.Name);
                    //Ya actualizamos el que apunta a un tipo que no es alias
                    //Ahora vamos de atras hacia delante por la cadena y actualizamos el tipo de todos
                    for (int i = result[result.Count - 1].Count - 1; i >= 0; i--) {
                        //Cogemos el i-esimo alias
                        var a = result[result.Count - 1][i];
                        //Cogemos el tipo al que apunta
                        t = scope.GetType(a.AliasType);
                        //Actualizamos el alias, diciendo que va a ser del mismo tipo al que el apunta
                        scope.Add(t, a.Name, updateIfExists: true);
                        //Ya no procesaremos mas este alias
                        dictAliases.Remove(a.Name);
                    }

                    //Creamos un nuevo grupo
                    result.Add(new List<AliasDeclarationNode>());
                    if (dictAliases.Count != 0) {
                        //Si todavia quedan alias por analizar, nos quedamos con uno cualquiera
                        alias = dictAliases[dictAliases.First().Key];
                    }
                }
                    //Si el tipo apunta no ha sido 100% definido y esta apuntando a un tipo que es una alias...
                else {
                    //Lo anadimos al grupo actual
                    result[result.Count - 1].Add(alias);
                    //Cogemos el proximo (al que el apunta)
                    alias = dictAliases[alias.AliasType];
                    //Si ese tipo al que apunta ya ha sido anadido en este grupo => Hay un ciclo
                    //Notar que si estuviera en otro grupo, no hubiera problema, porque significa que ya fue resuelto correctamente sin siclos
                    if (result[result.Count - 1].Contains(alias)) {
                        //Existe un ciclo y terminamo
                        errors.Add(new CyclicAliasesError(alias.Line, alias.Column));
                        break;
                    }
                }
            }

            return result;
        }
Beispiel #30
0
 /// <summary>
 /// Procesa un conjunto de declaraciones de un mismo tipo
 /// </summary>
 /// <param name="group"></param>
 /// <param name="scope"> </param>
 private void Process(IList<DeclarationNode> group, Scope scope, IList<Error> errors)
 {
     var first = group[0];
     //TODO: Refactorizar: Usar clases en vez de if - else if - else if...
     //Si es un grupo de declaraciones de variables
     if (first is VariableDeclarationNode) {
         ProcessVariableDeclarations(group, scope, errors);
     }
         //Si es un grupo de declaraciones de funciones/procedimientos
     else if (first is CallableDeclarationNode) {
         ProcessCallableDeclarations(group, scope, errors);
     }
         //Si es un grupo de declaraciones de tipos (records, arrays, etc)
     else {
         ProcessTypeDeclarations(group, scope, errors);
     }
 }