internal async Task <LocalizedAssemblyView> GetCoreLibrary(ParserContext parser) { ExternalAssemblyMetadata coreLib = await this.GetAssemblyMetadataFromAnyPossibleKey("en", "Core"); string name = coreLib.GetName(parser.CurrentLocale); return(await this.GetOrImportAssembly(parser, null, name)); }
public void RegisterDependencies(ExternalAssemblyMetadata assembly) { if (this.directDependencies == null) { this.directDependencies = new Dictionary <string, ExternalAssemblyMetadata>(); } this.directDependencies[assembly.ID] = assembly; }
public CompilationScope( ParserContext context, ExternalAssemblyMetadata metadata, Locale locale, ProgrammingLanguage programmingLanguage) { this.Locale = locale; this.ProgrammingLanguage = programmingLanguage; this.ScopeNumId = context.ScopeIdAlloc++; this.Metadata = metadata; this.ScopeKey = this.Metadata.CanonicalKey; }
public bool IsAllowedImport(ExternalAssemblyMetadata fromAssembly) { if (this.IsImportRestricted) { // Non-empty list means it must be only accessible from a specific library and not top-level user code. if (fromAssembly.IsUserDefined) { return(false); } // Is the current library on the list? return(this.OnlyImportableFrom.Contains(fromAssembly.ID)); } return(true); }
private static void LibraryDepTreeFlattenerRecursive( Dictionary <string, ExternalAssemblyMetadata> libsOut, ExternalAssemblyMetadata current) { string id = current.ID; if (!libsOut.ContainsKey(id)) { libsOut[id] = current; foreach (ExternalAssemblyMetadata dep in current.DirectDependencies) { LibraryDepTreeFlattenerRecursive(libsOut, dep); } } }
private static ExternalAssemblyMetadata CreateRootAssembly(Locale locale) { ExternalAssemblyMetadata m = new ExternalAssemblyMetadata(); m.ID = "."; m.InternalLocale = locale; m.CanonicalKey = "."; m.SupportedLocales = new HashSet <Locale>() { locale }; m.OnlyImportableFrom = new HashSet <string>(); m.IsUserDefined = true; return(m); }
private static void LibraryUsagePostOrderTraversal( ExternalAssemblyMetadata libraryToUse, List <ExternalAssemblyMetadata> libraryOrderOut, HashSet <ExternalAssemblyMetadata> usedLibraries, HashSet <ExternalAssemblyMetadata> cycleCheck, Stack <ExternalAssemblyMetadata> breadcrumbs) { if (usedLibraries.Contains(libraryToUse)) { return; } breadcrumbs.Push(libraryToUse); if (cycleCheck.Contains(libraryToUse)) { System.Text.StringBuilder message = new System.Text.StringBuilder(); message.Append("There is a dependency cycle in your libraries: "); bool first = true; foreach (ExternalAssemblyMetadata breadcrumb in breadcrumbs) { if (first) { first = false; } else { message.Append(" -> "); } message.Append(breadcrumb.ID); } throw new InvalidOperationException(message.ToString()); } cycleCheck.Add(libraryToUse); foreach (ExternalAssemblyMetadata dependency in libraryToUse.DirectDependencies) { LibraryUsagePostOrderTraversal(dependency, libraryOrderOut, usedLibraries, cycleCheck, breadcrumbs); } cycleCheck.Remove(libraryToUse); breadcrumbs.Pop(); usedLibraries.Add(libraryToUse); libraryOrderOut.Add(libraryToUse); }
private async Task <ExternalAssemblyMetadata> GetAssemblyMetadataFromAnyPossibleKey(string localeId, string name) { string key = (localeId == null || localeId == "") ? name : (localeId + ":" + name); if (!this.assemblyCache.ContainsKey(key)) { Dictionary <string, object> response = await this.wax.SendRequest("assembly", new Dictionary <string, object>() { { "command", "GetAssemblyMetadataFromAnyPossibleKey" }, { "locale", localeId }, { "name", name }, { "localDeps", this.localDeps }, { "projectDir", this.projectDirectory }, { "includeSource", true }, }); if (!(bool)response["found"]) { this.assemblyCache[key] = null; } else { Dictionary <string, string> nameByLocale = DictionaryUtil.FlattenedDictionaryToDictionary((string[])response["nameByLocale"]); Dictionary <string, string> sourceCode = DictionaryUtil.FlattenedDictionaryToDictionary((string[])response["sourceCode"]); ExternalAssemblyMetadata md = new ExternalAssemblyMetadata() { ID = (string)response["id"], IsUserDefined = false, InternalLocale = Locale.Get((string)response["internalLocale"]), SupportedLocales = new HashSet <Locale>(((string[])response["supportedLocales"]).Select(id => Locale.Get(id))), NameByLocale = nameByLocale, OnlyImportableFrom = new HashSet <string>((string[])response["onlyImportableFrom"]), SourceCode = sourceCode, }; md.CanonicalKey = md.InternalLocale.ID + ":" + md.ID; this.assemblyCache[key] = md; foreach (Locale applicableLocale in md.SupportedLocales) { this.assemblyCache[applicableLocale.ID + ":" + nameByLocale[applicableLocale.ID]] = md; } } } return(this.assemblyCache[key]); }
public ParserContext(CompileRequest compileRequest, Wax.WaxHub waxHub) { this.ClassIdAlloc = 1; this.ScopeIdAlloc = 1; this.CompileRequest = compileRequest; this.ProjectId = compileRequest.ProjectId; this.DelegateMainTo = compileRequest.DelegateMainTo; this.TypeContext = new TypeContext(); Locale rootLocale = compileRequest.CompilerLocale; ExternalAssemblyMetadata userDefinedAssembly = CreateRootAssembly(compileRequest.CompilerLocale); CompilationScope userDefinedScope = new CompilationScope(this, userDefinedAssembly, rootLocale, compileRequest.RootProgrammingLanguage); this.PushScope(userDefinedScope); this.ScopeManager = new ScopeManager(compileRequest, waxHub); this.NamespacePrefixLookupForCurrentFile = new List <string>(); this.ConstantAndEnumResolutionState = new Dictionary <TopLevelEntity, ConstantResolutionState>(); this.LiteralLookup = new LiteralLookup(); }
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); }