private static bool MergeClassTablesWithNewClass(ISealableDictionary <string, IImportedClass> importedClassTable, string className, IImportedClass mergedClassItem, IImport importLocation, BaseNode.ImportType mergedImportType, IErrorList errorList)
        {
            bool Success = true;

            foreach (KeyValuePair <string, IImportedClass> ImportedEntry in importedClassTable)
            {
                IImportedClass ClassItem = ImportedEntry.Value;
                if (ClassItem.Item == mergedClassItem.Item)
                {
                    string OldName = ImportedEntry.Key;
                    errorList.AddError(new ErrorClassAlreadyImported(importLocation, OldName, className));
                    Success = false;
                    break;
                }
            }

            // First time this class is imported, use the merge import type specification and location since they are known.
            if (Success)
            {
                mergedClassItem.SetImportType(mergedImportType);
                mergedClassItem.SetImportLocation(importLocation);

                importedClassTable.Add(className, mergedClassItem);
            }

            return(Success);
        }
        /// <summary>
        /// Merges a class import with previous imports.
        /// </summary>
        /// <param name="importedClassTable">The already resolved imports.</param>
        /// <param name="mergedClassTable">The new classes to import.</param>
        /// <param name="importLocation">The import location.</param>
        /// <param name="mergedImportType">The import specification for all <paramref name="mergedClassTable"/>.</param>
        /// <param name="errorList">List of errors found.</param>
        /// <returns>True if the merge is successful.</returns>
        public static bool MergeClassTables(ISealableDictionary <string, IImportedClass> importedClassTable, ISealableDictionary <string, IImportedClass> mergedClassTable, IImport importLocation, BaseNode.ImportType mergedImportType, IErrorList errorList)
        {
            bool Success = true;

            foreach (KeyValuePair <string, IImportedClass> Entry in mergedClassTable)
            {
                string         ClassName       = Entry.Key;
                IImportedClass MergedClassItem = Entry.Value;

                // The merged class may have an import specification already, but if so it must match the one used here.
                // We can assume we use mergedImportType after this.
                if (MergedClassItem.IsTypeAssigned && MergedClassItem.ImportType != mergedImportType)
                {
                    errorList.AddError(new ErrorImportTypeConflict(importLocation, ClassName));
                    Success = false;
                }

                // If a class is already imported with this name somehow.
                if (importedClassTable.ContainsKey(ClassName))
                {
                    // It must be the same class.
                    IImportedClass ClassItem = importedClassTable[ClassName];
                    if (ClassItem.Item != MergedClassItem.Item)
                    {
                        errorList.AddError(new ErrorNameAlreadyUsed(importLocation, ClassName));
                        Success = false;
                        continue;
                    }

                    // If the already existing imported class has a specification, it must match the one use for merge.
                    if (ClassItem.IsTypeAssigned)
                    {
                        if (ClassItem.ImportType != mergedImportType)
                        {
                            errorList.AddError(new ErrorImportTypeConflict(importLocation, ClassName));
                            Success = false;
                            continue;
                        }
                    }
                    else
                    {
                        ClassItem.SetImportType(mergedImportType);
                    }

                    // If the import location isn't specified yet, use the imported library.
                    if (!ClassItem.IsLocationAssigned)
                    {
                        ClassItem.SetImportLocation(importLocation);
                    }
                }
                else
                {
                    // New class, at least by name. Make sure it's not an already imported class using a different name.
                    Success &= MergeClassTablesWithNewClass(importedClassTable, ClassName, MergedClassItem, importLocation, mergedImportType, errorList);
                }
            }

            Debug.Assert(Success || !errorList.IsEmpty);
            return(Success);
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="ImportedClass"/> class.
        /// </summary>
        /// <param name="other">The other imported class.</param>
        public ImportedClass(IImportedClass other)
        {
            Item = other.Item;

            IsTypeAssigned = other.IsTypeAssigned;
            if (IsTypeAssigned)
            {
                _ImportType = other.ImportType;
            }

            IsLocationAssigned = other.IsLocationAssigned;
            if (IsLocationAssigned)
            {
                _ImportLocation = other.ImportLocation;
            }
        }
Exemple #4
0
        /// <summary>
        /// Checks for errors before applying a rule.
        /// </summary>
        /// <param name="node">The node instance to check.</param>
        /// <param name="dataList">Optional data collected during inspection of sources.</param>
        /// <param name="data">Private data to give to Apply() upon return.</param>
        /// <returns>True if an error occured.</returns>
        public override bool CheckConsistency(IInheritance node, IDictionary <ISourceTemplate, object> dataList, out object data)
        {
            bool Success = true;

            IClass      EmbeddingClass  = node.EmbeddingClass;
            IIdentifier ClassIdentifier = null;
            IClass      BaseClass       = null;

            if (node.ParentType is ISimpleType AsSimpleType)
            {
                ClassIdentifier = (IIdentifier)AsSimpleType.ClassIdentifier;
            }
            else if (node.ParentType is IGenericType AsGenericType)
            {
                ClassIdentifier = (IIdentifier)AsGenericType.ClassIdentifier;
            }

            if (ClassIdentifier != null)
            {
                Debug.Assert(ClassIdentifier.ValidText.IsAssigned);
                string ValidIdentifier = ClassIdentifier.ValidText.Item;

                ISealableDictionary <string, IImportedClass> ImportedClassTable = EmbeddingClass.ImportedClassTable;

                if (ValidIdentifier.ToUpperInvariant() == LanguageClasses.Any.Name.ToUpperInvariant())
                {
                    BaseClass = Class.ClassAny;
                }
                else if (ValidIdentifier.ToUpperInvariant() == LanguageClasses.AnyReference.Name.ToUpperInvariant())
                {
                    BaseClass = Class.ClassAnyReference;
                }
                else if (ValidIdentifier.ToUpperInvariant() == LanguageClasses.AnyValue.Name.ToUpperInvariant())
                {
                    BaseClass = Class.ClassAnyValue;
                }
                else if (ImportedClassTable.ContainsKey(ValidIdentifier))
                {
                    IImportedClass Imported = ImportedClassTable[ValidIdentifier];
                    BaseClass = Imported.Item;
                }
            }

            data = BaseClass;

            return(Success);
        }
        /// <summary>
        /// Validates a class import clauses.
        /// </summary>
        /// <param name="libraryTable">Imported libraries.</param>
        /// <param name="classTable">Imported classes.</param>
        /// <param name="errorList">List of errors found.</param>
        /// <returns>True if imports are valid.</returns>
        public virtual bool CheckClassConsistency(ISealableDictionary <string, ISealableDictionary <string, ILibrary> > libraryTable, ISealableDictionary <string, ISealableDictionary <string, IClass> > classTable, IErrorList errorList)
        {
            bool Success = true;

            // Process all import clauses separately.
            foreach (IImport ImportItem in ImportList)
            {
                if (!ImportItem.CheckImportConsistency(libraryTable, out ILibrary MatchingLibrary, errorList))
                {
                    Success = false;
                    continue;
                }

                if (ImportedLibraryList.Contains(MatchingLibrary))
                {
                    Success = false;
                    errorList.AddError(new ErrorDuplicateImport((IIdentifier)ImportItem.LibraryIdentifier, MatchingLibrary.ValidLibraryName, MatchingLibrary.ValidSourceName));
                    continue;
                }

                if (!Library.MergeImports(ImportedClassTable, ImportItem, MatchingLibrary, errorList))
                {
                    Success = false;
                    continue;
                }

                ImportedLibraryList.Add(MatchingLibrary);
            }

            // Check import specifications.
            foreach (KeyValuePair <string, IImportedClass> Entry in ImportedClassTable)
            {
                IImportedClass Imported = Entry.Value;
                if (Imported.Item == this)
                {
                    string NewName = Entry.Key;

                    if (NewName != ValidClassName)
                    {
                        Success = false;
                        errorList.AddError(new ErrorNameChanged(Imported.ImportLocation, ValidClassName, NewName));
                    }

                    if (Imported.IsTypeAssigned && Imported.ImportType != BaseNode.ImportType.Latest)
                    {
                        Success = false;
                        errorList.AddError(new ErrorImportTypeConflict(Imported.ImportLocation, ValidClassName));
                    }

                    break;
                }
            }

            // If not referenced by an imported library, a class should be able to reference itself.
            if (!ImportedClassTable.ContainsKey(ValidClassName))
            {
                IImportedClass SelfImport = new ImportedClass(this, BaseNode.ImportType.Latest);
                ImportedClassTable.Add(ValidClassName, SelfImport);

#if COVERAGE
                string ImportString = SelfImport.ToString();
#endif
            }

            foreach (KeyValuePair <string, IImportedClass> Entry in ImportedClassTable)
            {
                IImportedClass Imported = Entry.Value;
                Imported.SetParentSource(this);
            }

            ImportedClassTable.Seal();

            Debug.Assert(Success || !errorList.IsEmpty);
            return(Success);
        }
        private bool IsTypeReady(ISimpleType node, out object data)
        {
            data = null;
            bool IsReady = true;

            ITypeName     ValidTypeName = null;
            ICompiledType ValidType     = null;
            IError        Error         = null;

            IClass   EmbeddingClass   = node.EmbeddingClass;
            IFeature EmbeddingFeature = node.EmbeddingFeature;

            IIdentifier ClassIdentifier = (IIdentifier)node.ClassIdentifier;

            Debug.Assert(ClassIdentifier.ValidText.IsAssigned);
            string ValidIdentifier = ClassIdentifier.ValidText.Item;

            ISealableDictionary <string, IImportedClass> ImportedClassTable = EmbeddingClass.ImportedClassTable;
            ISealableDictionary <string, ICompiledType>  LocalGenericTable  = EmbeddingClass.LocalGenericTable;
            ISealableDictionary <IFeatureName, ISealableDictionary <string, IClass> > LocalExportTable = EmbeddingClass.LocalExportTable;
            ISealableDictionary <IFeatureName, ITypedefType>     LocalTypedefTable  = EmbeddingClass.LocalTypedefTable;
            ISealableDictionary <IFeatureName, IDiscrete>        LocalDiscreteTable = EmbeddingClass.LocalDiscreteTable;
            ISealableDictionary <IFeatureName, IFeatureInstance> LocalFeatureTable  = EmbeddingClass.LocalFeatureTable;

            IsReady &= ImportedClassTable.IsSealed;
            IsReady &= LocalGenericTable.IsSealed;
            IsReady &= LocalExportTable.IsSealed;
            IsReady &= LocalTypedefTable.IsSealed;
            IsReady &= LocalDiscreteTable.IsSealed;
            IsReady &= LocalFeatureTable.IsSealed;
            IsReady &= EmbeddingClass.ResolvedClassType.IsAssigned;

            if (IsReady)
            {
                if (ValidIdentifier.ToUpperInvariant() == LanguageClasses.Any.Name.ToUpperInvariant())
                {
                    GetBaseClassType(Class.ClassAny, out ValidTypeName, out ValidType);
                }
                else if (ValidIdentifier.ToUpperInvariant() == LanguageClasses.AnyReference.Name.ToUpperInvariant())
                {
                    GetBaseClassType(Class.ClassAnyReference, out ValidTypeName, out ValidType);
                }
                else if (ValidIdentifier.ToUpperInvariant() == LanguageClasses.AnyValue.Name.ToUpperInvariant())
                {
                    GetBaseClassType(Class.ClassAnyValue, out ValidTypeName, out ValidType);
                }
                else if (ImportedClassTable.ContainsKey(ValidIdentifier))
                {
                    IImportedClass Imported  = ImportedClassTable[ValidIdentifier];
                    IClass         BaseClass = Imported.Item;
                    IsReady = CheckValidityAsClass(BaseClass, out ValidTypeName, out ValidType, out bool IsInvalidGeneric);

                    if (IsInvalidGeneric)
                    {
                        Error = new ErrorGenericClass(ClassIdentifier, ValidIdentifier);
                    }
                }
                else if (LocalGenericTable.ContainsKey(ValidIdentifier))
                {
                    IFormalGenericType FormalGeneric = (IFormalGenericType)LocalGenericTable[ValidIdentifier];
                    GetGenericType(FormalGeneric, out ValidTypeName, out ValidType);
                }
                else if (FeatureName.TableContain(LocalTypedefTable, ValidIdentifier, out IFeatureName Key, out ITypedefType DefinedType))
                {
                    IsReady = CheckValidityAsTypedef(DefinedType, out ValidTypeName, out ValidType);
                }
                else
                {
                    Error = new ErrorUnknownIdentifier(ClassIdentifier, ValidIdentifier);
                }
            }
Exemple #7
0
        /// <summary>
        /// Checks for errors before applying a rule.
        /// </summary>
        /// <param name="node">The node instance to check.</param>
        /// <param name="dataList">Optional data collected during inspection of sources.</param>
        /// <param name="data">Private data to give to Apply() upon return.</param>
        /// <returns>True if an error occured.</returns>
        public override bool CheckConsistency(IGenericType node, IDictionary <ISourceTemplate, object> dataList, out object data)
        {
            bool Success = true;

            data = null;

            IIdentifier ClassIdentifier = (IIdentifier)node.ClassIdentifier;

            Debug.Assert(ClassIdentifier.ValidText.IsAssigned);
            string ValidIdentifier = ClassIdentifier.ValidText.Item;
            IClass EmbeddingClass  = node.EmbeddingClass;
            ISealableDictionary <string, IImportedClass> ImportedClassTable = EmbeddingClass.ImportedClassTable;

            ISealableDictionary <string, ICompiledType> ResolvedTable = new SealableDictionary <string, ICompiledType>();
            ISealableDictionary <string, IObjectType>   LocationTable = new SealableDictionary <string, IObjectType>();

            if (!ImportedClassTable.ContainsKey(ValidIdentifier))
            {
                AddSourceError(new ErrorUnknownIdentifier(ClassIdentifier, ValidIdentifier));
                Success = false;
            }
            else
            {
                TypeArgumentStyles ArgumentStyle = TypeArgumentStyles.None;

                foreach (ITypeArgument Item in node.TypeArgumentList)
                {
                    Success &= IsTypeArgumentValid(Item, ref ArgumentStyle);
                }

                IImportedClass Imported  = ImportedClassTable[ValidIdentifier];
                IClass         BaseClass = Imported.Item;

                if (BaseClass.GenericList.Count == 0)
                {
                    AddSourceError(new ErrorGenericClass(node, ValidIdentifier));
                    Success = false;
                }

                if (Success)
                {
                    bool IsHandled = false;

                    switch (ArgumentStyle)
                    {
                    case TypeArgumentStyles.None:
                    case TypeArgumentStyles.Positional:
                        Success   = CheckPositionalTypeArgumentsValidity(node, BaseClass, ResolvedTable, LocationTable);
                        IsHandled = true;
                        break;

                    case TypeArgumentStyles.Assignment:
                        Success   = CheckAssignmentTypeArgumentsValidity(node, BaseClass, ResolvedTable, LocationTable);
                        IsHandled = true;
                        break;
                    }

                    Debug.Assert(IsHandled);

                    if (Success)
                    {
                        ClassType.ResolveType(EmbeddingClass.TypeTable, BaseClass, ResolvedTable, EmbeddingClass.ResolvedClassType.Item, out ITypeName ValidResolvedTypeName, out ICompiledType ValidResolvedType);
                        data = new Tuple <IClass, TypeArgumentStyles, ISealableDictionary <string, ICompiledType>, ISealableDictionary <string, IObjectType>, ITypeName, ICompiledType>(BaseClass, ArgumentStyle, ResolvedTable, LocationTable, ValidResolvedTypeName, ValidResolvedType);
                    }
                }
            }

            return(Success);
        }