public LocalizedLibraryView GetCoreLibrary(ParserContext parser)
        {
            string          anyValidCoreLibId = "en:Core";
            LibraryMetadata coreLib           = this.libraryFinder.GetLibraryMetadataFromAnyPossibleKey(anyValidCoreLibId);
            string          name = coreLib.GetName(parser.CurrentLocale);

            return(this.GetOrImportLibrary(parser, null, name));
        }
        public bool IsAllowedImport(LibraryMetadata currentLibrary)
        {
            if (this.IsImportRestricted)
            {
                // Non-empty list means it must be only accessible from a specific library and not top-level user code.
                if (currentLibrary == null)
                {
                    return(false);
                }

                // Is the current library on the list?
                return(this.OnlyImportableFrom.Contains(currentLibrary.ID));
            }
            return(true);
        }
        private LocalizedLibraryView GetOrImportLibraryImpl(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;
            LibraryMetadata libraryMetadata    = this.libraryFinder.GetLibraryMetadataFromAnyPossibleKey(fromLocale.ID + ":" + name);
            Locale          effectiveLocale    = fromLocale;

            if (libraryMetadata == null)
            {
                libraryMetadata = this.libraryFinder.GetLibraryMetadataFromAnyPossibleKey(name);
                if (libraryMetadata != null &&
                    libraryMetadata.SupportedLocales.Contains(fromLocale) &&
                    libraryMetadata.InternalLocale != fromLocale)
                {
                    // Coincidental cross-language collision.
                    return(null);
                }

                if (libraryMetadata == null)
                {
                    // Simply no matches at all.
                    return(null);
                }

                effectiveLocale = libraryMetadata.InternalLocale;
            }

            // Are there any restrictions on importing that library from this location?
            if (!libraryMetadata.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.importedLibrariesByLocalizedName.ContainsKey(effectiveLocale))
            {
                this.importedLibrariesByLocalizedName[effectiveLocale] = new Dictionary <string, LocalizedLibraryView>();
            }
            if (!this.importedLibrariesByLocalizedName.ContainsKey(libraryMetadata.InternalLocale))
            {
                this.importedLibrariesByLocalizedName[libraryMetadata.InternalLocale] = new Dictionary <string, LocalizedLibraryView>();
            }

            // Check to see if this library has been imported before.
            if (this.importedLibrariesById.ContainsKey(libraryMetadata.ID))
            {
                // Is it imported by the same locale?
                if (this.importedLibrariesByLocalizedName[effectiveLocale].ContainsKey(name))
                {
                    // Then just return the previous instance as-is.
                    return(this.importedLibrariesByLocalizedName[effectiveLocale][name]);
                }

                // Wrap the previous instance in the new locale.
                LocalizedLibraryView output = new LocalizedLibraryView(effectiveLocale, this.importedLibrariesById[libraryMetadata.ID]);
                this.importedLibrariesByLocalizedName[effectiveLocale][output.Name] = output;
                return(output);
            }

            // If the library 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.
            LibraryCompilationScope libraryScope = new LibraryCompilationScope(parser.BuildContext, libraryMetadata);

            this.librariesAlreadyImportedIndexByKey[libraryMetadata.CanonicalKey] = this.ImportedLibraries.Count;
            this.ImportedLibraries.Add(libraryScope);
            this.importedLibrariesById[libraryMetadata.ID] = libraryScope;
            LocalizedLibraryView localizedView = new LocalizedLibraryView(effectiveLocale, libraryScope);

            this.importedLibrariesByLocalizedName[effectiveLocale][name] = localizedView;

            // Parse the library.
            parser.PushScope(libraryScope);
            Dictionary <string, string> embeddedCode = libraryMetadata.GetEmbeddedCode();

            foreach (string embeddedFile in embeddedCode.Keys.OrderBy(s => s.ToLower()))
            {
                string fakeName = "[" + embeddedFile + "]";
                string code     = embeddedCode[embeddedFile];
                parser.ParseInterpretedCode(fakeName, code);
            }
            parser.PopScope();

            return(localizedView);
        }
Beispiel #4
0
 public LibraryCompilationScope(BuildContext buildContext, LibraryMetadata library) : base(buildContext)
 {
     this.Library              = library;
     this.scopeKey             = library.CanonicalKey;
     this.Library.LibraryScope = this;
 }
        private static LibraryMetadata[] GetAvailableLibraryPathsByLibraryName(
            string nullableBuildFileCrayonPath,
            string nullableProjectDirectory)
        {
            string crayonHome = System.Environment.GetEnvironmentVariable("CRAYON_HOME");

#if RELEASE
            if (crayonHome == null)
            {
                throw new System.InvalidOperationException("Please set the CRAYON_HOME environment variable to the location of the directory containing both 'crayon.exe' and the 'lib' directory.");
            }
#endif

            string placesWhereLibraryDirectoriesCanExist = "";

            if (crayonHome != null)
            {
                placesWhereLibraryDirectoriesCanExist += ";" + FileUtil.JoinPath(crayonHome, "libs");
            }
            if (nullableBuildFileCrayonPath != null)
            {
                placesWhereLibraryDirectoriesCanExist += ";" + nullableBuildFileCrayonPath;
            }
            placesWhereLibraryDirectoriesCanExist += ";" + (System.Environment.GetEnvironmentVariable("CRAYON_PATH") ?? "");

#if OSX
            placesWhereLibraryDirectoriesCanExist = placesWhereLibraryDirectoriesCanExist.Replace(':', ';');
#endif
            string[]      paths = placesWhereLibraryDirectoriesCanExist.Split(new char[] { ';' }, System.StringSplitOptions.RemoveEmptyEntries);
            List <string> unverifiedLibraryDirectories = new List <string>();
            foreach (string path in paths)
            {
                // TODO: figure out why this says nullable yet is being used directly.
                string absolutePath = FileUtil.GetAbsolutePathFromRelativeOrAbsolutePath(nullableProjectDirectory, path);
                if (FileUtil.DirectoryExists(absolutePath))
                {
                    unverifiedLibraryDirectories.AddRange(FileUtil.DirectoryListDirectoryPaths(absolutePath));
                }
            }

#if DEBUG
            // Presumably running from source. Walk up to the root directory and find the Libraries directory.
            // From there use the list of folders.
            string currentDirectory = FileUtil.GetCurrentDirectory();
            while (!string.IsNullOrEmpty(currentDirectory))
            {
                string path = FileUtil.JoinPath(currentDirectory, "Libraries");
                if (FileUtil.DirectoryExists(path) &&
                    FileUtil.FileExists(FileUtil.JoinPath(currentDirectory, "Compiler", "CrayonWindows.sln"))) // quick sanity check
                {
                    unverifiedLibraryDirectories.AddRange(FileUtil.DirectoryListDirectoryPaths(path));
                    break;
                }
                currentDirectory = FileUtil.GetParentDirectory(currentDirectory);
            }
#endif
            List <string> verifiedLibraryPaths = new List <string>();

            foreach (string dir in unverifiedLibraryDirectories)
            {
                string manifestPath = FileUtil.JoinPath(dir, "manifest.json");
                if (FileUtil.FileExists(manifestPath))
                {
                    verifiedLibraryPaths.Add(dir);
                }
            }

            // Library name collisions will override any previous definition.
            // For example, a custom library referenced by a build file will override a built-in library.
            // An example use case of this would be to define a custom library called "Gamepad" for mobile that puts
            // buttons in the corners of the screen, but without having to change any code to be platform-aware.
            Dictionary <string, LibraryMetadata> uniqueLibraries = new Dictionary <string, LibraryMetadata>();
            foreach (string path in verifiedLibraryPaths)
            {
                string          defaultName = FileUtil.GetFileNameFromPath(path);
                LibraryMetadata metadata    = new LibraryMetadata(path, defaultName);

                // TODO: don't hardcode EN
                string uniqueKey = "en:" + metadata.ID;
                uniqueLibraries[uniqueKey] = metadata;
            }

            return(uniqueLibraries.Values
                   .OrderBy(metadata => metadata.ID.ToLower())
                   .ToArray());
        }