Example #1
0
        private ICollection <TypeSymbol> ImportAssemblies(string applicationAssemblyName, MetadataSource mdSource, string intermediaryAssembly = null)
        {
            importedTypes = new List <TypeSymbol>();
            var isApplicationAssembly = Path.GetFullPath(mdSource.CoreAssemblyPath) == intermediaryAssembly;

            ImportScriptAssembly(applicationAssemblyName, mdSource, mdSource.CoreAssemblyPath, coreAssembly: true, applicationAssembly: isApplicationAssembly);

            foreach (TypeSymbol typeSymbol in importedTypes)
            {
                if (typeSymbol.Type == SymbolType.Class &&
                    typeSymbol.Name.Equals(nameof(Array), StringComparison.Ordinal))
                {
                    // Array is special - it is used to build other Arrays of more
                    // specific types we load members for in the second pass...
                    ImportMembers(typeSymbol);
                }
            }

            foreach (TypeSymbol typeSymbol in importedTypes)
            {
                if (typeSymbol.IsGeneric)
                {
                    // Generics are also special - they are used to build other generic instances
                    // with specific types for generic arguments as we load members for other
                    // types subsequently...
                    ImportMembers(typeSymbol);
                }
            }

            foreach (TypeSymbol typeSymbol in importedTypes)
            {
                if (typeSymbol.IsGeneric == false &&
                    (typeSymbol.Type != SymbolType.Class ||
                     typeSymbol.Name.Equals(nameof(Array), StringComparison.Ordinal) == false))
                {
                    ImportMembers(typeSymbol);
                }

                // There is some special-case logic to be performed on some members of the
                // global namespace.

                if (typeSymbol.Type == SymbolType.Class)
                {
                    if (typeSymbol.Name.Equals("Script", StringComparison.Ordinal))
                    {
                        // The Script class contains additional pseudo global methods that cannot
                        // be referenced at compile-time by the app author, but can be
                        // referenced by generated code during compilation.
                        ImportPseudoMembers(PseudoClassMembers.Script, (ClassSymbol)typeSymbol);
                    }
                    else if (typeSymbol.Name.Equals(nameof(Object), StringComparison.Ordinal))
                    {
                        // We need to add a static GetType method

                        ImportPseudoMembers(PseudoClassMembers.Object, (ClassSymbol)typeSymbol);
                    }
                    else if (typeSymbol.Name.Equals(typeof(Dictionary <,>).Name, StringComparison.Ordinal))
                    {
                        // The Dictionary class contains static methods at runtime, rather
                        // than instance methods.

                        ImportPseudoMembers(PseudoClassMembers.Dictionary, (ClassSymbol)typeSymbol);
                    }
                    else if (typeSymbol.Name.Equals("Arguments", StringComparison.Ordinal))
                    {
                        // We need to add a static indexer, which isn't allowed in C#

                        ImportPseudoMembers(PseudoClassMembers.Arguments, (ClassSymbol)typeSymbol);
                    }
                }
            }

            // Import all the types first.
            // Types need to be loaded upfront so that they can be used in resolving types associated
            // with members.
            foreach (string assemblyPath in mdSource.Assemblies)
            {
                isApplicationAssembly = Path.GetFullPath(assemblyPath) == intermediaryAssembly;
                ImportScriptAssembly(applicationAssemblyName, mdSource, assemblyPath, coreAssembly: false, applicationAssembly: isApplicationAssembly);
            }

            // Resolve Base Types
            foreach (TypeSymbol typeSymbol in importedTypes)
            {
                if (typeSymbol is ClassSymbol classSymbol)
                {
                    ImportBaseType(classSymbol);
                    BuildInterfaceAssociations(classSymbol);
                }
                else if (typeSymbol.Type == SymbolType.Interface)
                {
                    ImportInterfaces((InterfaceSymbol)typeSymbol);
                }
            }

            // Import members
            foreach (TypeSymbol typeSymbol in importedTypes)
            {
                if (typeSymbol.IsCoreType)
                {
                    // already processed above
                    continue;
                }

                ImportMembers(typeSymbol);
            }

            foreach (TypeSymbol typeSymbol in importedTypes)
            {
                if (typeSymbol is ClassSymbol classSymbol && classSymbol.IsPublic)
                {
                    foreach (var method in GetExtensionMethods(typeSymbol.Members))
                    {
                        ParameterDefinition parameter = ((MethodDefinition)method.ParseContext).Parameters.First();
                        symbols.AddExtensionMethod(method, parameter.ParameterType.FullName, false);
                    }
                }
            }

            return(importedTypes);
        }
Example #2
0
        private void ImportType(MetadataSource mdSource, TypeDefinition type, bool inScriptCoreAssembly, bool inApplicationAssembly,
                                ScriptReference dependency, TypeSymbol outerType = null)
        {
            if (!type.IsPublic && !type.IsNestedPublic && dependency?.InternalesVisible == false)
            {
                return;
            }

            if (inScriptCoreAssembly && MetadataHelpers.ShouldImportScriptCoreType(type) == false)
            {
                return;
            }

            string name          = outerType is TypeSymbol ? $"{outerType.Name}${type.Name}" : type.Name;
            string namespaceName = outerType is TypeSymbol ? outerType.Namespace : type.Namespace;

            bool   dummy;
            string scriptName = MetadataHelpers.GetScriptName(type, out dummy, out dummy);

            NamespaceSymbol namespaceSymbol = symbols.GetNamespace(namespaceName);
            TypeSymbol      typeSymbol      = null;

            if (type.IsInterface)
            {
                typeSymbol = new InterfaceSymbol(name, namespaceSymbol);
            }
            else if (MetadataHelpers.IsEnum(type))
            {
                // NOTE: We don't care about the flags bit on imported enums
                //       because this is only consumed by the generation logic.
                typeSymbol = new EnumerationSymbol(name, namespaceSymbol, /* flags */ false);

                if (MetadataHelpers.ShouldUseEnumNames(type))
                {
                    ((EnumerationSymbol)typeSymbol).SetNamedValues();
                }
                else if (MetadataHelpers.ShouldUseEnumValues(type))
                {
                    ((EnumerationSymbol)typeSymbol).SetNumericValues();
                }
            }
            else if (MetadataHelpers.IsDelegate(type))
            {
                typeSymbol = new DelegateSymbol(name, namespaceSymbol);
                typeSymbol.SetTransformedName("Function");
                typeSymbol.SetIgnoreGenerics();
                typeSymbol.SetIgnoreNamespace();
            }
            else
            {
                if (MetadataHelpers.ShouldTreatAsRecordType(type))
                {
                    typeSymbol = new RecordSymbol(name, namespaceSymbol);
                    typeSymbol.SetTransformedName(nameof(Object));
                }
                else
                {
                    typeSymbol = new ClassSymbol(name, namespaceSymbol);
                }
            }

            if (typeSymbol != null)
            {
                if (MetadataHelpers.ShouldIgnoreGenerics(type, out var useGenericName))
                {
                    typeSymbol.SetIgnoreGenerics(useGenericName);
                }

                if (type.HasGenericParameters)
                {
                    List <GenericParameterSymbol> genericArguments = new List <GenericParameterSymbol>();

                    foreach (GenericParameter genericParameter in type.GenericParameters)
                    {
                        GenericParameterSymbol arg =
                            new GenericParameterSymbol(genericParameter.Position, genericParameter.Name, true, symbols.GlobalNamespace);

                        genericArguments.Add(arg);
                    }

                    typeSymbol.AddGenericParameters(genericArguments);
                }

                string dependencyName = MetadataHelpers.GetScriptDependencyName(type, out string dependencyIdentifier);

                if (dependencyName != null)
                {
                    dependency = ScriptReferenceProvider.Instance.GetReference(dependencyName, dependencyIdentifier);
                }

                if (!inApplicationAssembly)
                {
                    typeSymbol.SetImported(dependency);
                }

                typeSymbol.SetMetadataToken(type, inScriptCoreAssembly);

                bool ignoreNamespace = MetadataHelpers.ShouldIgnoreNamespace(type);

                if (ignoreNamespace || dependency == null || string.IsNullOrEmpty(dependency.Identifier))
                {
                    typeSymbol.SetIgnoreNamespace();
                }
                else
                {
                    typeSymbol.ScriptNamespace = dependency.Identifier;
                }

                //todo: improve the logic here to support private/protected access modifiers for nested classes
                typeSymbol.IsPublic   = type.IsPublic;
                typeSymbol.IsInternal = type.IsNotPublic;

                if (string.IsNullOrEmpty(scriptName) == false)
                {
                    typeSymbol.SetTransformedName(scriptName);
                }

                SetArrayTypeMetadata(type, typeSymbol, scriptName);

                typeSymbol.SetSource(dependency);
                namespaceSymbol.AddType(typeSymbol);
                importedTypes.Add(typeSymbol);

                if (outerType is TypeSymbol)
                {
                    outerType.AddType(typeSymbol);
                }

                if (type.HasNestedTypes)
                {
                    foreach (TypeDefinition nestedType in type.NestedTypes)
                    {
                        ImportType(mdSource, nestedType, inScriptCoreAssembly, inApplicationAssembly, dependency, typeSymbol);
                    }
                }
            }
        }
Example #3
0
        private void ImportType(MetadataSource mdSource, TypeDefinition type, bool inScriptCoreAssembly,
                                string scriptNamespace)
        {
            if (type.IsPublic == false)
            {
                return;
            }

            if (inScriptCoreAssembly && MetadataHelpers.ShouldImportScriptCoreType(type) == false)
            {
                return;
            }

            string name          = type.Name;
            string namespaceName = type.Namespace;

            bool   dummy;
            string scriptName = MetadataHelpers.GetScriptName(type, out dummy, out dummy);

            NamespaceSymbol namespaceSymbol = symbols.GetNamespace(namespaceName);
            TypeSymbol      typeSymbol      = null;

            if (type.IsInterface)
            {
                typeSymbol = new InterfaceSymbol(name, namespaceSymbol);
            }
            else if (MetadataHelpers.IsEnum(type))
            {
                // NOTE: We don't care about the flags bit on imported enums
                //       because this is only consumed by the generation logic.
                typeSymbol = new EnumerationSymbol(name, namespaceSymbol, /* flags */ false);

                if (MetadataHelpers.ShouldUseEnumNames(type))
                {
                    ((EnumerationSymbol)typeSymbol).SetNamedValues();
                }
                else if (MetadataHelpers.ShouldUseEnumValues(type))
                {
                    ((EnumerationSymbol)typeSymbol).SetNumericValues();
                }
            }
            else if (MetadataHelpers.IsDelegate(type))
            {
                typeSymbol = new DelegateSymbol(name, namespaceSymbol);
                typeSymbol.SetTransformedName("Function");
            }
            else
            {
                if (MetadataHelpers.ShouldTreatAsRecordType(type))
                {
                    typeSymbol = new RecordSymbol(name, namespaceSymbol);
                    typeSymbol.SetTransformedName(nameof(Object));
                }
                else
                {
                    typeSymbol = new ClassSymbol(name, namespaceSymbol);

                    if (MetadataHelpers.IsScriptExtension(type, out string extendee))
                    {
                        ((ClassSymbol)typeSymbol).SetExtenderClass(extendee);
                    }
                }
            }

            if (typeSymbol != null)
            {
                if (type.HasGenericParameters)
                {
                    List <GenericParameterSymbol> genericArguments = new List <GenericParameterSymbol>();

                    foreach (GenericParameter genericParameter in type.GenericParameters)
                    {
                        GenericParameterSymbol arg =
                            new GenericParameterSymbol(genericParameter.Position, genericParameter.Name,
                                                       /* typeArgument */ true,
                                                       symbols.GlobalNamespace);
                        genericArguments.Add(arg);
                    }

                    typeSymbol.AddGenericParameters(genericArguments);
                }

                ScriptReference dependency     = null;
                string          dependencyName = MetadataHelpers.GetScriptDependencyName(type, out string dependencyIdentifier);

                if (dependencyName != null)
                {
                    dependency      = new ScriptReference(dependencyName, dependencyIdentifier);
                    scriptNamespace = dependency.Identifier;
                }

                typeSymbol.SetImported(dependency);
                typeSymbol.SetMetadataToken(type, inScriptCoreAssembly);

                bool ignoreNamespace = MetadataHelpers.ShouldIgnoreNamespace(type);

                if (ignoreNamespace || string.IsNullOrEmpty(scriptNamespace))
                {
                    typeSymbol.SetIgnoreNamespace();
                }
                else
                {
                    typeSymbol.ScriptNamespace = scriptNamespace;
                }

                typeSymbol.IsPublic = true;

                if (string.IsNullOrEmpty(scriptName) == false)
                {
                    typeSymbol.SetTransformedName(scriptName);
                }

                SetArrayTypeMetadata(type, typeSymbol, scriptName);

                namespaceSymbol.AddType(typeSymbol);
                importedTypes.Add(typeSymbol);
            }
        }