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); } } } }
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("Object"); } else { typeSymbol = new ClassSymbol(name, namespaceSymbol); string extendee; if (MetadataHelpers.IsScriptExtension(type, out extendee)) { ((ClassSymbol)typeSymbol).SetExtenderClass(extendee); } if (String.CompareOrdinal(scriptName, "Array") == 0) { typeSymbol.SetArray(); } } } 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 dependencyIdentifier; string dependencyName = MetadataHelpers.GetScriptDependencyName(type, out 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.SetPublic(); if (String.IsNullOrEmpty(scriptName) == false) { typeSymbol.SetTransformedName(scriptName); } namespaceSymbol.AddType(typeSymbol); _importedTypes.Add(typeSymbol); } }
public ICollection <TypeSymbol> BuildMetadata(ParseNodeList compilationUnits, SymbolSet symbols, CompilerOptions options) { Debug.Assert(compilationUnits != null); Debug.Assert(symbols != null); _symbols = symbols; _symbolTable = symbols; _options = options; string scriptName = GetAssemblyScriptName(compilationUnits); if (String.IsNullOrEmpty(scriptName)) { _errorHandler.ReportError("You must declare a ScriptAssembly attribute.", String.Empty); } else if (Utility.IsValidScriptName(scriptName) == false) { string errorMessage = "The ScriptAssembly attribute referenced an invalid name '{0}'. Script names must only contain letters, numbers, dots or underscores."; _errorHandler.ReportError(String.Format(errorMessage, scriptName), String.Empty); } symbols.ScriptName = scriptName; string scriptPrefix = GetAssemblyScriptPrefix(compilationUnits); if (String.IsNullOrEmpty(scriptPrefix) == false) { if (Utility.IsValidIdentifier(scriptPrefix) == false) { string errorMessage = "The ScriptQualifier attribute referenced an invalid prefix '{0}'. Script prefix must be valid identifiers."; _errorHandler.ReportError(String.Format(errorMessage, scriptPrefix), String.Empty); } } else { scriptPrefix = scriptName.Replace(".", String.Empty); } symbols.ScriptPrefix = scriptPrefix; string assemblyScriptNamespace = GetAssemblyScriptNamespace(compilationUnits); List <TypeSymbol> types = new List <TypeSymbol>(); // Build all the types first. // Types need to be loaded upfront so that they can be used in resolving types associated // with members. foreach (CompilationUnitNode compilationUnit in compilationUnits) { foreach (NamespaceNode namespaceNode in compilationUnit.Members) { string namespaceName = namespaceNode.Name; NamespaceSymbol namespaceSymbol = symbols.GetNamespace(namespaceName); List <string> imports = null; Dictionary <string, string> aliases = null; ParseNodeList usingClauses = namespaceNode.UsingClauses; if ((usingClauses != null) && (usingClauses.Count != 0)) { foreach (ParseNode usingNode in namespaceNode.UsingClauses) { if (usingNode is UsingNamespaceNode) { if (imports == null) { imports = new List <string>(usingClauses.Count); } string referencedNamespace = ((UsingNamespaceNode)usingNode).ReferencedNamespace; if (imports.Contains(referencedNamespace) == false) { imports.Add(referencedNamespace); } } else { Debug.Assert(usingNode is UsingAliasNode); if (aliases == null) { aliases = new Dictionary <string, string>(); } UsingAliasNode aliasNode = (UsingAliasNode)usingNode; aliases[aliasNode.Alias] = aliasNode.TypeName; } } } // Add parent namespaces as imports in reverse order since they // are searched in that fashion. string[] namespaceParts = namespaceName.Split('.'); for (int i = namespaceParts.Length - 2; i >= 0; i--) { string partialNamespace; if (i == 0) { partialNamespace = namespaceParts[0]; } else { partialNamespace = String.Join(".", namespaceParts, 0, i + 1); } if (imports == null) { imports = new List <string>(); } if (imports.Contains(partialNamespace) == false) { imports.Add(partialNamespace); } } // Build type symbols for all user-defined types foreach (TypeNode typeNode in namespaceNode.Members) { UserTypeNode userTypeNode = typeNode as UserTypeNode; if (userTypeNode == null) { continue; } // Check if we have overriding script namespace for this type. string typeScriptNamespace = GetScriptNamespace(userTypeNode.Attributes); if (String.IsNullOrEmpty(typeScriptNamespace)) { typeScriptNamespace = assemblyScriptNamespace; } ClassSymbol partialTypeSymbol = null; bool isPartial = false; if ((userTypeNode.Modifiers & Modifiers.Partial) != 0) { partialTypeSymbol = (ClassSymbol)((ISymbolTable)namespaceSymbol).FindSymbol(userTypeNode.Name, /* context */ null, SymbolFilter.Types); if ((partialTypeSymbol != null) && partialTypeSymbol.IsApplicationType) { // This class will be considered as a partial class isPartial = true; // Merge code model information for the partial class onto the code model node // for the primary partial class. Interesting bits of information include things // such as base class etc. that is yet to be processed. CustomTypeNode partialTypeNode = (CustomTypeNode)partialTypeSymbol.ParseContext; partialTypeNode.MergePartialType((CustomTypeNode)userTypeNode); // Merge interesting bits of information onto the primary type symbol as well // representing this partial class BuildType(partialTypeSymbol, userTypeNode); if (String.IsNullOrEmpty(typeScriptNamespace) == false) { partialTypeSymbol.ScriptNamespace = typeScriptNamespace; } } } TypeSymbol typeSymbol = BuildType(userTypeNode, namespaceSymbol); if (typeSymbol != null) { typeSymbol.SetParseContext(userTypeNode); typeSymbol.SetParentSymbolTable(symbols); if (imports != null) { typeSymbol.SetImports(imports); } if (aliases != null) { typeSymbol.SetAliases(aliases); } if (String.IsNullOrEmpty(typeScriptNamespace) == false) { typeSymbol.ScriptNamespace = typeScriptNamespace; } if (isPartial == false) { namespaceSymbol.AddType(typeSymbol); } else { // Partial types don't get added to the namespace, so we don't have // duplicated named items. However, they still do get instantiated // and processed as usual. // // The members within partial classes refer to the partial type as their parent, // and hence derive context such as the list of imports scoped to the // particular type. // However, the members will get added to the primary partial type's list of // members so they can be found. // Effectively the partial class here gets created just to hold // context of type-symbol level bits of information such as the list of // imports, that are consumed when generating code for the members defined // within a specific partial class. ((ClassSymbol)typeSymbol).SetPrimaryPartialClass(partialTypeSymbol); } types.Add(typeSymbol); } } } } // Build inheritance chains foreach (TypeSymbol typeSymbol in types) { if (typeSymbol.Type == SymbolType.Class) { BuildTypeInheritance((ClassSymbol)typeSymbol); } } // Import members foreach (TypeSymbol typeSymbol in types) { BuildMembers(typeSymbol); } // Associate interface members with interface member symbols foreach (TypeSymbol typeSymbol in types) { if (typeSymbol.Type == SymbolType.Class) { BuildInterfaceAssociations((ClassSymbol)typeSymbol); } } // Load resource values if (_symbols.HasResources) { foreach (TypeSymbol typeSymbol in types) { if (typeSymbol.Type == SymbolType.Resources) { BuildResources((ResourcesSymbol)typeSymbol); } } } // Load documentation if (_options.EnableDocComments) { Stream docCommentsStream = options.DocCommentFile.GetStream(); if (docCommentsStream != null) { try { XmlDocument docComments = new XmlDocument(); docComments.Load(docCommentsStream); symbols.SetComments(docComments); } finally { options.DocCommentFile.CloseStream(docCommentsStream); } } } return(types); }
private void ImportType(MetadataSource mdSource, TypeDefinition type, bool inScriptCoreAssembly, string assemblyScriptNamespace, string assemblyScriptName) { if (type.IsPublic == false) { return; } if (inScriptCoreAssembly && (MetadataHelpers.ShouldImportScriptCoreType(type) == false)) { return; } string name = type.Name; string namespaceName = type.Namespace; string scriptNamespace = MetadataHelpers.GetScriptNamespace(type); string scriptName = MetadataHelpers.GetScriptName(type); if (String.IsNullOrEmpty(scriptNamespace) && (String.IsNullOrEmpty(assemblyScriptNamespace) == false)) { scriptNamespace = assemblyScriptNamespace; } 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); } else { typeSymbol = new ClassSymbol(name, namespaceSymbol); string mixinRoot; if (MetadataHelpers.ShouldGlobalizeMembers(type, out mixinRoot)) { ((ClassSymbol)typeSymbol).SetGlobalMethods(mixinRoot); } } } 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); } typeSymbol.SetImported(assemblyScriptName); typeSymbol.SetMetadataToken(type, inScriptCoreAssembly); bool ignoreNamespace = MetadataHelpers.ShouldIgnoreNamespace(type); if (ignoreNamespace) { typeSymbol.SetIgnoreNamespace(); } typeSymbol.SetPublic(); if (String.IsNullOrEmpty(scriptNamespace) == false) { typeSymbol.ScriptNamespace = scriptNamespace; } if (String.IsNullOrEmpty(scriptName) == false) { typeSymbol.SetTransformedName(scriptName); } namespaceSymbol.AddType(typeSymbol); _importedTypes.Add(typeSymbol); } }