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
 private void AddStringVariable(string name, Scope s = null)
 {
     if (s == null)
         _scope.Add(name, StringType.Create());
     else {
         s.Add(name, StringType.Create());
     }
 }
Beispiel #3
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 #4
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 #5
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)
        {
            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);
        }
        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 #8
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 #9
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;
        }
        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)
        {
            //Si ya se definio ese nombre anteriormente (en este scope solamente)
            if (scope.ExistsVariableOrCallable(Name, false)) {
                errors.Add(new AlreadyDefinedError(Line, Column, Name));
                return;
            }

            int errorsCount = errors.Count;

            //Chequeamos la semantica de la expresion que estamos asignando
            Body.CheckSemantic(scope, errors);

            //Si hubo errores en el chequeo semantico...
            if (errorsCount != errors.Count) {
                return;
            }

            errorsCount = errors.Count;

            //Si me especificaron el tipo
            TigerType resultType = null;

            if (Type != null) {
                //Si el tipo no existe
                if (!scope.ExistsType(Type)) {
                    errors.Add(new UndefinedTypeError(Line, Column, Type));
                }

                //Guardamos el tipo que debe almacenar esta variable (segun su definicion)
                resultType = scope.GetType(Type);

                //Si el tipo de retorno de la expresion es diferente al del especificado explicitamente
                if (Body.ReturnType != resultType) {
                    //Debemos chequear el caso se este asignando Nil a un tipo que lo permita
                    if (!(Body.ReturnType is NilType) || !NilType.CanBeAssignedTo(resultType)) {
                        errors.Add(new UnexpectedTypeError(Line, Column, resultType, Body.ReturnType));
                    }

                }
            }
            //Si no me especificaron el tipo
            else {
                //Si no tiene tipo de retorno
                if (!Body.ReturnsValue()) {
                    errors.Add(new NonValueAssignmentError(Line, Column, Name));
                }
                //Si el tipo de retorno es Nil, no es valido pues no se puede inferir el tipo de la variable que estamos declarando
                else if (Body.ReturnType is NilType) {
                    errors.Add(new NilAssignmentError(Line, Column, Name));
                }
            }

            //Si no hubo ningun error...
            if (errorsCount == errors.Count) {
                //Finalmente anadimos la variable declarada al scope
                scope.Add(Name, Body.ReturnType is NilType ? resultType : Body.ReturnType);
                //Guardamos la variable en el nodo para poder usarla en la generacion de codigo
                Variable = scope.GetVariable(Name, false);
            }
        }