Esempio n. 1
0
        public override void CheckSemantics(Scope scope, List <SemanticError> errors)
        {
            //--------------------------------------------------
            // Por Default, El Nodo No Tiene Errores.
            //--------------------------------------------------
            this.IsOk = true;

            //--------------------------------------------------
            // Obtener Todos Los Nombres De Los Tipos En El
            // Bloque Actual.
            //--------------------------------------------------
            string[] names = this.Declarations.Select(x => x.ID.Name).ToArray <string>();

            //--------------------------------------------------
            // Comprobar Que Todos Los Nombres Se Declaren Solo
            // Una Vez.
            //--------------------------------------------------
            for (int i = 0; i < names.Length; i++)
            {
                bool hasPreviousDeclaration = (scope.FindLocalTypeInfo(names[i]) != null);
                for (int j = 0; j < i; j++)
                {
                    if (names[i] == names[j])
                    {
                        hasPreviousDeclaration = true;
                    }
                }
                if (hasPreviousDeclaration)
                {
                    errors.Add(SemanticError.PreviousTypeDeclaration(names[i], this.Declarations[i]));
                    this.IsOk = false;
                }
            }

            if (!this.IsOk)
            {
                return;
            }

            //--------------------------------------------------
            // Buscar Ciclos En Las Declaraciones AliasTypeNode
            // Y ArrayTypeNode.
            //--------------------------------------------------
            bool[] visited = new bool[this.Declarations.Length];

            //--------------------------------------------------
            // Actualizar 'Scope' Solamente Con Declaraciones De Records.
            //--------------------------------------------------
            for (int i = 0; i < this.Declarations.Length; i++)
            {
                if (this.Declarations[i].TypeNode is RecordTypeNode)
                {
                    visited[i] = true;
                    scope.Add(new TypeInfo(this.Declarations[i].ID.Name, this.Declarations[i].TypeNode));
                }
            }

            for (int i = 0; i < names.Length && this.IsOk; i++)
            {
                if (visited[i])
                {
                    continue;
                }

                List <int> path = new List <int>();

                int currentDeclaration = i;
                while (true)
                {
                    //--------------------------------------------------
                    // Si La Declaración Ha Sido Visitada Previamente,
                    // Entonces Estamos En Presencia  De  Un  Ciclo.
                    //--------------------------------------------------
                    if (visited[currentDeclaration])
                    {
                        errors.Add(SemanticError.CycleInTypeDeclaration(
                                       this.Declarations[currentDeclaration].ID.Name, this
                                       ));
                        this.IsOk = false;
                        break;
                    }

                    //--------------------------------------------------
                    // Marcar Como "Visitada" La Declaración Actual.
                    //--------------------------------------------------
                    path.Add(currentDeclaration);
                    visited[currentDeclaration] = true;

                    //--------------------------------------------------
                    // Buscar El Nombre Del Tipo Del Que Depende La
                    // Declaración Actual:
                    //
                    // type <type-id> = <type-id>
                    // type <type-id> = array of <type-id>
                    //--------------------------------------------------
                    var CDN = this.Declarations.ElementAt(currentDeclaration).TypeNode;

                    string type = CDN is AliasTypeNode ? (CDN as AliasTypeNode).TypeID.Name :
                                  (CDN as ArrayTypeNode).TypeID.Name;

                    //--------------------------------------------------
                    // Buscar Primero Si Depende De Un Tipo En Este Bloque
                    // De Declaraciones.
                    //--------------------------------------------------
                    int namesIndex = Array.FindIndex(this.Declarations, x => x.ID.Name == type);

                    //--------------------------------------------------
                    // Si El Tipo No Esta En El Bloque De Declaraciones,
                    // Buscar En El Scope Global. De Lo Contrario, Buscar
                    // En El Scope Local.
                    //--------------------------------------------------
                    TypeInfo TI = null;
                    if (namesIndex < 0 || namesIndex >= names.Length)
                    {
                        TI = scope.FindTypeInfo(type);
                    }
                    else
                    {
                        TI = scope.FindLocalTypeInfo(type);
                    }

                    //--------------------------------------------------
                    // Si El Tipo Está En El Scope, Actualizar Cada Una
                    // De Las Declaraciones.
                    //--------------------------------------------------
                    if (TI != null)
                    {
                        var TN = TI.TypeNode;

                        for (int u = path.Count - 1; u >= 0; u--)
                        {
                            var declarationNode = this.Declarations[path[u]];
                            if (declarationNode.TypeNode is AliasTypeNode)
                            {
                                (declarationNode.TypeNode as AliasTypeNode).AliasOf = TN;
                            }
                            else
                            {
                                (declarationNode.TypeNode as ArrayTypeNode).ArrayOf = TN;
                                TN = declarationNode.TypeNode;
                            }
                            scope.Add(new TypeInfo(declarationNode.ID.Name, TN));
                        }
                        break;
                    }

                    //--------------------------------------------------
                    // Si No Se Pudo Encontrar El Tipo , Entonces Comprobar
                    // Si Depende De Alguna Declaración En El Mismo Bloque.
                    // Si No Es El Caso, Reportar Error.
                    //--------------------------------------------------
                    currentDeclaration = namesIndex;

                    if (currentDeclaration < 0 || currentDeclaration >= names.Length)
                    {
                        errors.Add(SemanticError.TypeDoesNotExist(type, CDN));
                        this.IsOk = false;
                        break;
                    }
                }
            }

            //--------------------------------------------------
            // Si Hay Errores, Parar De Reportar Errores.
            //--------------------------------------------------
            if (!this.IsOk)
            {
                return;
            }

            //--------------------------------------------------
            // Hacer 'CheckSemantics' A Cada TypeDeclarationNode.
            //--------------------------------------------------
            foreach (var declaration in this.Declarations)
            {
                declaration.CheckSemantics(scope, errors);
                this.IsOk &= declaration.IsOk;
            }
        }