internal async Task <LocalizedAssemblyView> GetOrImportAssembly(ParserContext parser, Token throwToken, string fullImportNameWithDots) { LocalizedAssemblyView asmView = await this.GetOrImportAssemblyImpl(parser, throwToken, fullImportNameWithDots); if (asmView != null && asmView.Scope != parser.CurrentScope) { parser.CurrentScope.AddDependency(throwToken, asmView); } return(asmView); }
internal void AddDependency(Token throwToken, LocalizedAssemblyView view) { if (this.dependenciesAndViews.ContainsKey(view.Scope)) { if (this.dependenciesAndViews[view.Scope] != view) { throw ParserException.ThrowException( view.Locale, ErrorMessages.CANNOT_IMPORT_SAME_LIBRARY_FROM_DIFFERENT_LOCALES, throwToken); } } this.dependenciesAndViews[view.Scope] = view; this.Metadata.RegisterDependencies(view.Scope.Metadata); }
public async Task ParseFile(string filename, string code) { FileScope fileScope = new FileScope(filename, code, this.CurrentScope, this.GetNextFileId()); this.RegisterFileUsed(fileScope, code); TokenStream tokens = new TokenStream(fileScope); List <string> namespaceImportsBuilder = new List <string>(); // Implicitly import the Core library for the current locale. LocalizedAssemblyView implicitCoreImport = await this.ScopeManager.GetCoreLibrary(this); namespaceImportsBuilder.Add(implicitCoreImport.Name); fileScope.Imports.Add(new ImportStatement(null, implicitCoreImport.Name, fileScope)); while (tokens.HasMore && tokens.IsNext(this.Keywords.IMPORT)) { ImportStatement importStatement = this.TopLevelParser.ParseImport(tokens, fileScope); if (importStatement == null) { throw new Exception(); } namespaceImportsBuilder.Add(importStatement.ImportPath); LocalizedAssemblyView localizedAssemblyView = await this.ScopeManager.GetOrImportAssembly(this, importStatement.FirstToken, importStatement.ImportPath); if (localizedAssemblyView == null) { this.unresolvedImports.Add(importStatement); } } string[] namespaceImports = namespaceImportsBuilder.ToArray(); while (tokens.HasMore) { this.CurrentScope.AddExecutable(this.TopLevelParser.Parse(tokens, null, fileScope)); } }
private async Task <LocalizedAssemblyView> GetOrImportAssemblyImpl(ParserContext parser, Token throwToken, string fullImportNameWithDots) { // TODO: allow importing from a user-specified locale Locale fromLocale = parser.CurrentLocale; string name = fullImportNameWithDots.Contains('.') ? fullImportNameWithDots.Split('.')[0] : fullImportNameWithDots; string secondAttemptedKey = name; ExternalAssemblyMetadata assemblyMetadata = await this.GetAssemblyMetadataFromAnyPossibleKey(fromLocale.ID, name); Locale effectiveLocale = fromLocale; if (assemblyMetadata == null) { assemblyMetadata = await this.GetAssemblyMetadataFromAnyPossibleKey(null, name); if (assemblyMetadata != null && assemblyMetadata.SupportedLocales.Contains(fromLocale) && assemblyMetadata.InternalLocale != fromLocale) { // Coincidental cross-language collision. return(null); } if (assemblyMetadata == null) { // Simply no matches at all. return(null); } effectiveLocale = assemblyMetadata.InternalLocale; } // Are there any restrictions on importing that library from this location? if (!assemblyMetadata.IsAllowedImport(parser.CurrentLibrary)) { throw new ParserException(throwToken, "This library cannot be imported from here."); } // Ensure all secondary lookups for each locale is instantiated to make the upcoming code more readable. if (!this.importedAssembliesByLocalizedName.ContainsKey(effectiveLocale)) { this.importedAssembliesByLocalizedName[effectiveLocale] = new Dictionary <string, LocalizedAssemblyView>(); } if (!this.importedAssembliesByLocalizedName.ContainsKey(assemblyMetadata.InternalLocale)) { this.importedAssembliesByLocalizedName[assemblyMetadata.InternalLocale] = new Dictionary <string, LocalizedAssemblyView>(); } // Check to see if this library has been imported before. if (this.importedAssembliesById.ContainsKey(assemblyMetadata.ID)) { // Is it imported by the same locale? if (this.importedAssembliesByLocalizedName[effectiveLocale].ContainsKey(name)) { // Then just return the previous instance as-is. return(this.importedAssembliesByLocalizedName[effectiveLocale][name]); } // Wrap the previous instance in the new locale. LocalizedAssemblyView output = new LocalizedAssemblyView(effectiveLocale, this.importedAssembliesById[assemblyMetadata.ID]); this.importedAssembliesByLocalizedName[effectiveLocale][output.Name] = output; return(output); } Dictionary <string, string> sourceCode = assemblyMetadata.SourceCode; string arbitraryFilename = sourceCode.Keys.Where(t => t.Contains('.')).Select(t => t.ToLowerInvariant()).FirstOrDefault(); ProgrammingLanguage programmingLanguage = arbitraryFilename != null && arbitraryFilename.EndsWith(".acr") ? ProgrammingLanguage.ACRYLIC : ProgrammingLanguage.CRAYON; // If the assembly exists but hasn't been imported before, instantiate it and // add it to all the lookups. This needs to happen before parsing the embedded // code to prevent infinite recursion. CompilationScope compilationScope = new CompilationScope(parser, assemblyMetadata, assemblyMetadata.InternalLocale, programmingLanguage); this.assembliesAlreadyImportedIndexByKey[assemblyMetadata.CanonicalKey] = this.ImportedAssemblyScopes.Count; this.ImportedAssemblyScopes.Add(compilationScope); this.importedAssembliesById[assemblyMetadata.ID] = compilationScope; LocalizedAssemblyView localizedView = new LocalizedAssemblyView(effectiveLocale, compilationScope); this.importedAssembliesByLocalizedName[effectiveLocale][name] = localizedView; // Parse the assembly. parser.PushScope(compilationScope); foreach (string file in sourceCode.Keys.OrderBy(s => s.ToLowerInvariant())) { string fakeName = "[" + file + "]"; string code = sourceCode[file]; await parser.ParseFile(fakeName, code); } parser.PopScope(); return(localizedView); }