// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "uLang/Common/Containers/SharedPointerArray.h" #include "uLang/Common/Misc/Optional.h" #include "uLang/Common/Text/UTF8String.h" #include "uLang/CompilerPasses/CompilerTypes.h" namespace uLang { class CArchive; class CSourcePackage; class CSourceProject; /** * Abstraction of a source file **/ class ISourceSnippet : public CSharedMix { public: virtual ~ISourceSnippet() {} /** * Globally unique path of this snippet, e.g. a fully qualified file path **/ virtual CUTF8String GetPath() const = 0; virtual void SetPath(const CUTF8String& Path) = 0; /** * Get text representation of this snippet * When the result is EResult::Unspecified, no text representation exists * When the result is EResult::Error, text representation exists, but an error occurred retrieving it **/ virtual TOptional GetText() const = 0; /** * Get Vst representation of this snippet * When the result is EResult::Unspecified, no Vst representation exists * When the result is EResult::Error, Vst representation exists, but an error occurred retrieving it **/ virtual TOptional> GetVst() const = 0; virtual void SetVst(TSRef Snippet) = 0; }; /** * A module **/ class CSourceModule : public CSharedMix { public: /// The source files contained in the module TSRefArray _SourceSnippets; /// Submodules of this module TSRefArray _Submodules; /// Construct from name CSourceModule(const CUTF8StringView& Name) : _Name(Name) {} virtual ~CSourceModule() = default; const CUTF8String& GetName() const { return _Name; } virtual const CUTF8String& GetFilePath() const { return CUTF8String::GetEmpty(); } VERSECOMPILER_API CUTF8StringView GetNameFromFile() const; VERSECOMPILER_API static CUTF8StringView GetNameFromFile(const CUTF8StringView& ModuleFilePath); VERSECOMPILER_API TOptional> FindSubmodule(const CUTF8StringView& ModuleName) const; VERSECOMPILER_API void AddSnippet(const uLang::TSRef& Snippet); VERSECOMPILER_API bool RemoveSnippet(const uLang::TSRef& Snippet, bool bRecursive); /// Visit this module and all its submodules /// Lambda returns true to continue visiting, false to terminate search /// Returns true if all modules have been visited, false if search was terminated early template bool VisitAll(FunctionType&& Lambda) const; template bool VisitAll(FunctionType&& Lambda); // non-const version /// For lookup by name ULANG_FORCEINLINE bool operator==(const CUTF8StringView& Name) const { return _Name == Name; } protected: /// Name of this module CUTF8String _Name; }; /** * A package of modules **/ class CSourcePackage : public CSharedMix { public: /// Settings of a package /// This mirrors FVersePackageSettings in the runtime struct SSettings { CUTF8String _VersePath; // Verse path of the root module of this package EVerseScope _VerseScope = EVerseScope::PublicUser; // Origin/visibility of Verse code in this package EPackageRole _Role = EPackageRole::Source; // The role this package plays in the project. TOptional _VerseVersion; // The language version the package targets. Note that this value is ignored for digests, which are assumed to target the latest unstable version. TOptional _UploadedAtFNVersion; // Only set for constraint `_Role`. bool _bTreatModulesAsImplicit = false; // If true, module macros in this package's source and digest will be treated as implicit TArray _DependencyPackages; // Names of packages this package is dependent on TOptional _VniDestDir; // Destination directory for VNI generated C++ code (fully qualified) bool _bAllowExperimental = false; // If true, this package can use experimental definitions (but cannot publish in UEFN). bool _bEnableSceneGraph = false; // If true, Scene Graph is enabled. This impacts the asset digest that is generated. bool _bDefsInClassesInAssetManifests = true; // See FVersePackageSettings::_bDefsInClassesInAssetManifests uint32_t GetUploadedAtFNVersion(uint32_t Default) const { return _UploadedAtFNVersion.Get(Default); } }; struct SVersionedDigest { TSRef _Snippet; uint32_t _EffectiveVerseVersion; TArray _DependencyPackages; }; /// Where the source code of this package originates enum EOrigin : uint8_t { Unknown, Memory, FileSystem }; /// The root module of this package, equivalent to the _VersePath specified in _Settings TSRef _RootModule; /// Optional digest to be used instead of source if desired TOptional _Digest; /// The public-only digest, if it exists. TOptional _PublicDigest; /// Construct from name CSourcePackage(const CUTF8StringView& Name, const TSRef& RootModule) : _RootModule(RootModule), _Name(Name) {} virtual ~CSourcePackage() = default; const CUTF8String& GetName() const { return _Name; } const SSettings& GetSettings() const { return _Settings; } virtual EOrigin GetOrigin() const { return EOrigin::Unknown; } virtual const CUTF8String& GetDirPath() const { return CUTF8String::GetEmpty(); } virtual const CUTF8String& GetFilePath() const { return CUTF8String::GetEmpty(); } VERSECOMPILER_API int32_t GetNumSnippets() const; void SetName(const CUTF8StringView& NewName) { _Name = NewName; } void SetVersePath(const CUTF8StringView& VersePath) { _Settings._VersePath = VersePath; } void SetVerseScope(const EVerseScope VerseScope) { _Settings._VerseScope = VerseScope; } void SetVerseVersion(const TOptional VerseVersion) { _Settings._VerseVersion = VerseVersion; } void SetAllowExperimental(const bool bAllowExperimental) { _Settings._bAllowExperimental = bAllowExperimental; } void SetRole(const EPackageRole Role) { _Settings._Role = Role; } void SetTreatDefinitionsAsImplicit(bool bTreatAsImplicit) { _Settings._bTreatModulesAsImplicit = bTreatAsImplicit; } VERSECOMPILER_API void SetDependencyPackages(TArray&& PackageNames); VERSECOMPILER_API void AddDependencyPackage(const CUTF8StringView& PackageName); VERSECOMPILER_API void TruncateVniDestDir(); // Strip parent path from VniDestDir VERSECOMPILER_API bool RemoveSnippet(const uLang::TSRef& Snippet); private: /// Name of this package CUTF8String _Name; protected: /// Settings, e.g. parsed from .vpackage file SSettings _Settings; }; /** * A project, holding packages and other information **/ class CSourceProject : public CSharedMix { public: /// Entry for a package contained in this project struct SPackage { TSPtr _Package; bool _bReadonly = false; }; /// The packages contained in this project TArray _Packages; /// Construct from name CSourceProject(const CUTF8StringView& Name) : _Name(Name) {} /// Construct from other project by making a shallow copy VERSECOMPILER_API CSourceProject(const CSourceProject& Other); virtual ~CSourceProject() = default; const CUTF8String& GetName() const { return _Name; } virtual const CUTF8String& GetFilePath() const { return CUTF8String::GetEmpty(); } VERSECOMPILER_API int32_t GetNumSnippets() const; VERSECOMPILER_API const SPackage* FindPackage(const CUTF8StringView& PackageName, const CUTF8StringView& PackageVersePath) const; VERSECOMPILER_API const SPackage& FindOrAddPackage(const CUTF8StringView& PackageName, const CUTF8StringView& PackageVersePath); VERSECOMPILER_API void AddSnippet(const uLang::TSRef& Snippet, const CUTF8StringView& PackageName, const CUTF8StringView& PackageVersePath); VERSECOMPILER_API bool RemoveSnippet(const uLang::TSRef& Snippet); VERSECOMPILER_API void TruncateVniDestDirs(); // Strip parent path from all VniDestDirs private: /// Name of this project CUTF8String _Name; }; /* Implementations *****************************************************************************/ template bool CSourceModule::VisitAll(FunctionType&& Lambda) const { if (!Lambda(*this)) { return false; } for (const TSRef& Submodule : _Submodules) { if (!Submodule->VisitAll(Lambda)) { return false; } } return true; } template bool CSourceModule::VisitAll(FunctionType&& Lambda) // non-const version { if (!Lambda(*this)) { return false; } for (const TSRef& Submodule : _Submodules) { if (!Submodule->VisitAll(Lambda)) { return false; } } return true; } }