// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "RigVMModel/RigVMGraph.h" #include "RigVMModel/Nodes/RigVMUnitNode.h" #include "RigVMModel/Nodes/RigVMVariableNode.h" #include "RigVMModel/Nodes/RigVMParameterNode.h" #include "RigVMModel/Nodes/RigVMCommentNode.h" #include "RigVMModel/Nodes/RigVMRerouteNode.h" #include "RigVMCore/RigVM.h" #include "RigVMCore/RigVMStruct.h" #include "RigVMCompiler/RigVMAST.h" #include "Logging/TokenizedMessage.h" #include "RigVMModel/Nodes/RigVMLibraryNode.h" #include "RigVMCompiler.generated.h" class URigVMFunctionReferenceNode; struct FRigVMGraphFunctionData; struct FRigVMGraphFunctionHeader; struct FRigVMFunctionCompilationData; USTRUCT(BlueprintType) struct RIGVMDEVELOPER_API FRigVMCompileSettings { GENERATED_BODY() public: FRigVMCompileSettings(); FRigVMCompileSettings(UScriptStruct* InExecuteContextScriptStruct); UScriptStruct* GetExecuteContextStruct() const { return ASTSettings.ExecuteContextStruct; } void SetExecuteContextStruct(UScriptStruct* InExecuteContextScriptStruct) { ASTSettings.ExecuteContextStruct = InExecuteContextScriptStruct; } UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = FRigVMCompileSettings) bool SurpressInfoMessages; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = FRigVMCompileSettings) bool SurpressWarnings; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = FRigVMCompileSettings) bool SurpressErrors; UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = FRigVMCompileSettings) bool EnablePinWatches; UPROPERTY(Transient) bool IsPreprocessorPhase; UPROPERTY(EditAnywhere, Transient, BlueprintReadWrite, Category = FRigVMCompileSettings) FRigVMParserASTSettings ASTSettings; UPROPERTY() bool SetupNodeInstructionIndex; UPROPERTY() bool ASTErrorsAsNotifications; UPROPERTY(EditAnywhere, AdvancedDisplay, BlueprintReadWrite, Category = FRigVMCompileSettings) bool bWarnAboutDeprecatedNodes; UPROPERTY(EditAnywhere, AdvancedDisplay, BlueprintReadWrite, Category = FRigVMCompileSettings) bool bWarnAboutDuplicateEvents; static FRigVMCompileSettings Fast(UScriptStruct* InExecuteContextStruct = nullptr) { FRigVMCompileSettings Settings(InExecuteContextStruct); Settings.EnablePinWatches = true; Settings.IsPreprocessorPhase = false; Settings.ASTSettings = FRigVMParserASTSettings::Fast(InExecuteContextStruct); return Settings; } static FRigVMCompileSettings Optimized(UScriptStruct* InExecuteContextStruct = nullptr) { FRigVMCompileSettings Settings(InExecuteContextStruct); Settings.EnablePinWatches = false; Settings.IsPreprocessorPhase = false; Settings.ASTSettings = FRigVMParserASTSettings::Optimized(InExecuteContextStruct); return Settings; } void ReportInfo(const FString& InMessage) const; void ReportWarning(const FString& InMessage) const; void ReportError(const FString& InMessage) const; template void ReportInfof(UE::Core::TCheckedFormatString Fmt, Types... Args) const { ReportInfo(FString::Printf(Fmt, Args...)); } template void ReportWarningf(UE::Core::TCheckedFormatString Fmt, Types... Args) const { ReportWarning(FString::Printf(Fmt, Args...)); } template void ReportErrorf(UE::Core::TCheckedFormatString Fmt, Types... Args) const { ReportError(FString::Printf(Fmt, Args...)); } void Report(EMessageSeverity::Type InSeverity, UObject* InSubject, const FString& InMessage) const { ASTSettings.Report(InSeverity, InSubject, InMessage); } template void Reportf(EMessageSeverity::Type InSeverity, UObject* InSubject, UE::Core::TCheckedFormatString Fmt, Types... Args) const { Report(InSeverity, InSubject, FString::Printf(Fmt, Args...)); } }; class RIGVMDEVELOPER_API FRigVMCompileSettingsDuringLoadGuard { public: FRigVMCompileSettingsDuringLoadGuard(FRigVMCompileSettings& InSettings) : ASTErrorsAsNotifications(InSettings.ASTErrorsAsNotifications, true) {} private: TGuardValue ASTErrorsAsNotifications; }; struct RIGVMDEVELOPER_API FRigVMCompilerWorkData { public: FRigVMCompileSettings Settings; bool bSetupMemory = false; URigVM* VM = nullptr; TArray Graphs; UScriptStruct* ExecuteContextStruct = nullptr; TMap* PinPathToOperand = nullptr; FRigVMExtendedExecuteContext* Context = nullptr; TMap ExprToOperand; TMap ExprComplete; TArray ExprToSkip; TArray TraversalExpressions; TMap ProcessedLinks; TMap TraitListLiterals; FRigVMOperand ComparisonOperand; using FRigVMASTProxyArray = TArray>; using FRigVMASTProxySourceMap = TMap; using FRigVMASTProxyTargetsMap = TMap; TMap CachedProxiesWithSharedOperand; const FRigVMASTProxySourceMap* ProxySources = nullptr; FRigVMASTProxyTargetsMap ProxyTargets; TMap> BranchInfos; struct FFunctionRegisterData { TSoftObjectPtr ReferenceNode; ERigVMMemoryType MemoryType = ERigVMMemoryType::Invalid; int32 RegisterIndex = 0; friend inline uint32 GetTypeHash(const FFunctionRegisterData& Data) { uint32 Result = HashCombine(GetTypeHash(Data.ReferenceNode.ToSoftObjectPath().ToString()), GetTypeHash(Data.MemoryType)); return HashCombine(Result, GetTypeHash(Data.RegisterIndex)); } bool operator==(const FFunctionRegisterData& Other) const { return ReferenceNode == Other.ReferenceNode && MemoryType == Other.MemoryType && RegisterIndex == Other.RegisterIndex; } }; TMap FunctionRegisterToOperand; TArray WatchedPins; TMap> PropertyPathDescriptions; TMap> PropertyDescriptions; FRigVMOperand AddProperty(ERigVMMemoryType InMemoryType, const FName& InName, const FString& InCPPType, UObject* InCPPTypeObject, const FString& InDefaultValue = FString()); FRigVMOperand FindProperty(ERigVMMemoryType InMemoryType, const FName& InName) const; FRigVMPropertyDescription GetProperty(const FRigVMOperand& InOperand); int32 FindOrAddPropertyPath(const FRigVMOperand& InOperand, const FString& InHeadCPPType, const FString& InSegmentPath); const FProperty* GetPropertyForOperand(const FRigVMOperand& InOperand) const; TRigVMTypeIndex GetTypeIndexForOperand(const FRigVMOperand& InOperand) const; FName GetUniquePropertyName(ERigVMMemoryType InMemoryType, const FName& InDesiredName) const; TSharedPtr AST; struct FCopyOpInfo { FRigVMCopyOp Op; const FRigVMAssignExprAST* AssignExpr = nullptr; const FRigVMVarExprAST* SourceExpr = nullptr; const FRigVMVarExprAST* TargetExpr = nullptr; }; // operators that have been delayed for injection into the bytecode TMap DeferredCopyOps; struct FLazyBlockInfo { FLazyBlockInfo() : StartInstruction(INDEX_NONE) , EndInstruction(INDEX_NONE) , bProcessed(false) {} TOptional Hash; FString BlockCombinationName; FRigVMOperand ExecuteStateOperand; int32 StartInstruction; int32 EndInstruction; TArray Expressions; TArray RunInstructionsToUpdate; bool bProcessed; }; TMap> LazyBlocks; TArray LazyBlocksToProcess; TOptional CurrentBlockHash; void ReportInfo(const FString& InMessage) const; void ReportWarning(const FString& InMessage) const; void ReportError(const FString& InMessage) const; template void ReportInfof(UE::Core::TCheckedFormatString Fmt, Types... Args) const { ReportInfo(FString::Printf(Fmt, Args...)); } template void ReportWarningf(UE::Core::TCheckedFormatString Fmt, Types... Args) const { ReportWarning(FString::Printf(Fmt, Args...)); } template void ReportErrorf(UE::Core::TCheckedFormatString Fmt, Types... Args) const { ReportError(FString::Printf(Fmt, Args...)); } FRigVMReportDelegate OriginalReportDelegate; void OverrideReportDelegate(bool& bEncounteredASTError, bool& bSurpressedASTError); void RemoveOverrideReportDelegate(); void Clear() { if (VM) { if (Context) { VM->ClearMemory(*Context); VM->Reset(*Context); } else { VM->Reset_Internal(); } } Graphs.Reset(); if (PinPathToOperand) { PinPathToOperand->Reset(); } ExprToOperand.Reset(); ExprComplete.Reset(); ExprToSkip.Reset(); ProcessedLinks.Reset(); CachedProxiesWithSharedOperand.Reset(); ProxyTargets.Reset(); BranchInfos.Reset(); FunctionRegisterToOperand.Reset(); WatchedPins.Reset(); PropertyDescriptions.Reset(); PropertyPathDescriptions.Reset(); DeferredCopyOps.Reset(); } }; DECLARE_DELEGATE_RetVal_OneParam(const FRigVMFunctionCompilationData*, FRigVMCompiler_GetFunctionCompilationData, const FRigVMGraphFunctionHeader& Header); UCLASS(BlueprintType) class RIGVMDEVELOPER_API URigVMCompiler : public UObject { GENERATED_BODY() public: URigVMCompiler(); UPROPERTY() FRigVMCompileSettings Settings_DEPRECATED; UFUNCTION(BlueprintCallable, Category = FRigVMCompiler, meta=(DeprecatedFunction, DeprecationMessage="Compile is deprecated, use CompileVM with Context parameter.")) bool Compile(TArray InGraphs, URigVMController* InController, URigVM* OutVM) { return false; } UFUNCTION(BlueprintCallable, Category = FRigVMCompiler) bool CompileVM(TArray InGraphs, URigVMController* InController, URigVM* OutVM, FRigVMExtendedExecuteContext& Context) { return Compile(Settings_DEPRECATED, InGraphs, InController, OutVM, Context, TArray(), nullptr); } UE_DEPRECATED(5.3, "Please use Compile with Context param.") bool Compile(TArray InGraphs, URigVMController* InController, URigVM* OutVM, const TArray& InExternalVariables, TMap* OutOperands, TSharedPtr InAST = TSharedPtr(), FRigVMFunctionCompilationData* OutFunctionCompilationData = nullptr) { return false; } UE_DEPRECATED(5.4, "Please use CompileFunction with Settings param.") bool Compile(TArray InGraphs, URigVMController* InController, URigVM* OutVM, FRigVMExtendedExecuteContext& OutVMContext, const TArray& InExternalVariables, TMap* OutOperands, TSharedPtr InAST = TSharedPtr(), FRigVMFunctionCompilationData* OutFunctionCompilationData = nullptr); bool Compile(const FRigVMCompileSettings& InSettings, TArray InGraphs, URigVMController* InController, URigVM* OutVM, FRigVMExtendedExecuteContext& OutVMContext, const TArray& InExternalVariables, TMap* OutOperands, TSharedPtr InAST = TSharedPtr(), FRigVMFunctionCompilationData* OutFunctionCompilationData = nullptr); UE_DEPRECATED(5.3, "Please use CompileFunction with Context param.") bool CompileFunction(const URigVMLibraryNode* InLibraryNode, URigVMController* InController, FRigVMFunctionCompilationData* OutFunctionCompilationData) { return false; } UE_DEPRECATED(5.4, "Please use CompileFunction with Settings param.") bool CompileFunction(const URigVMLibraryNode* InLibraryNode, URigVMController* InController, FRigVMFunctionCompilationData* OutFunctionCompilationData, FRigVMExtendedExecuteContext& OutVMContext); bool CompileFunction(const FRigVMCompileSettings& InSettings, const URigVMLibraryNode* InLibraryNode, URigVMController* InController, const TArray& InExternalVariables, FRigVMFunctionCompilationData* OutFunctionCompilationData, FRigVMExtendedExecuteContext& OutVMContext); FRigVMCompiler_GetFunctionCompilationData GetFunctionCompilationData; TMap CompiledFunctions; static UScriptStruct* GetScriptStructForCPPType(const FString& InCPPType); static FString GetPinHash(const URigVMPin* InPin, const FRigVMVarExprAST* InVarExpr, bool bIsDebugValue = false, const URigVMLibraryNode* FunctionCompiling = nullptr, const FRigVMASTProxy& InPinProxy = FRigVMASTProxy()); // follows assignment expressions to find the source ref counted containers // since ref counted containers are not copied for assignments. // this is currently only used for arrays. static const FRigVMVarExprAST* GetSourceVarExpr(const FRigVMExprAST* InExpr); void MarkDebugWatch(const FRigVMCompileSettings& InSettings, bool bRequired, URigVMPin* InPin, URigVM* OutVM, TMap* OutOperands, TSharedPtr InRuntimeAST); private: const URigVMLibraryNode* CurrentCompilationFunction = nullptr; TSet FunctionCompilationStack; TArray GetLinkedPins(URigVMPin* InPin, bool bInputs = true, bool bOutputs = true, bool bRecursive = true); int32 GetElementSizeFromCPPType(const FString& InCPPType, UScriptStruct* InScriptStruct); static FString GetPinHashImpl(const URigVMPin* InPin, const FRigVMVarExprAST* InVarExpr, bool bIsDebugValue = false, const URigVMLibraryNode* FunctionCompiling = nullptr, const FRigVMASTProxy& InPinProxy = FRigVMASTProxy()); bool TraverseExpression(const FRigVMExprAST* InExpr, FRigVMCompilerWorkData& WorkData); bool TraverseChildren(const FRigVMExprAST* InExpr, FRigVMCompilerWorkData& WorkData); bool TraverseBlock(const FRigVMBlockExprAST* InExpr, FRigVMCompilerWorkData& WorkData); bool TraverseEntry(const FRigVMEntryExprAST* InExpr, FRigVMCompilerWorkData& WorkData); bool TraverseCallExtern(const FRigVMCallExternExprAST* InExpr, FRigVMCompilerWorkData& WorkData); bool TraverseInlineFunction(const FRigVMInlineFunctionExprAST* InExpr, FRigVMCompilerWorkData& WorkData); bool TraverseNoOp(const FRigVMNoOpExprAST* InExpr, FRigVMCompilerWorkData& WorkData); bool TraverseVar(const FRigVMVarExprAST* InExpr, FRigVMCompilerWorkData& WorkData); bool TraverseLiteral(const FRigVMVarExprAST* InExpr, FRigVMCompilerWorkData& WorkData); bool TraverseExternalVar(const FRigVMExternalVarExprAST* InExpr, FRigVMCompilerWorkData& WorkData); bool TraverseAssign(const FRigVMAssignExprAST* InExpr, FRigVMCompilerWorkData& WorkData); bool TraverseCopy(const FRigVMCopyExprAST* InExpr, FRigVMCompilerWorkData& WorkData); bool TraverseCachedValue(const FRigVMCachedValueExprAST* InExpr, FRigVMCompilerWorkData& WorkData); bool TraverseExit(const FRigVMExitExprAST* InExpr, FRigVMCompilerWorkData& WorkData); bool TraverseInvokeEntry(const FRigVMInvokeEntryExprAST* InExpr, FRigVMCompilerWorkData& WorkData); void AddCopyOperator( const FRigVMCopyOp& InOp, const FRigVMAssignExprAST* InAssignExpr, const FRigVMVarExprAST* InSourceExpr, const FRigVMVarExprAST* InTargetExpr, FRigVMCompilerWorkData& WorkData, bool bDelayCopyOperations = true); void AddCopyOperator( const FRigVMCompilerWorkData::FCopyOpInfo& CopyOpInfo, FRigVMCompilerWorkData& WorkData, bool bDelayCopyOperations = true); FRigVMOperand FindOrAddRegister(const FRigVMVarExprAST* InVarExpr, FRigVMCompilerWorkData& WorkData, bool bIsDebugValue = false); const FRigVMCompilerWorkData::FRigVMASTProxyArray& FindProxiesWithSharedOperand(const FRigVMVarExprAST* InVarExpr, FRigVMCompilerWorkData& WorkData); static FString GetPinNameWithDirectionPrefix(const URigVMPin* Pin); static int32 GetOperandFunctionInterfaceParameterIndex(const TArray& OperandsPinNames, const FRigVMFunctionCompilationData* FunctionCompilationData, const FRigVMOperand& Operand); bool ValidateNode(const FRigVMCompileSettings& InSettings, URigVMNode* InNode, bool bCheck = true); void ReportInfo(const FRigVMCompileSettings& InSettings, const FString& InMessage); void ReportWarning(const FRigVMCompileSettings& InSettings, const FString& InMessage); void ReportError(const FRigVMCompileSettings& InSettings, const FString& InMessage); template void ReportInfof(const FRigVMCompileSettings& InSettings, UE::Core::TCheckedFormatString Fmt, Types... Args) { ReportInfo(InSettings, FString::Printf(Fmt, Args...)); } template void ReportWarningf(const FRigVMCompileSettings& InSettings, UE::Core::TCheckedFormatString Fmt, Types... Args) { ReportWarning(InSettings, FString::Printf(Fmt, Args...)); } template void ReportErrorf(const FRigVMCompileSettings& InSettings, UE::Core::TCheckedFormatString Fmt, Types... Args) { ReportError(InSettings, FString::Printf(Fmt, Args...)); } friend class FRigVMCompilerImportErrorContext; friend class FFunctionCompilationScope; }; class RIGVMDEVELOPER_API FFunctionCompilationScope { public: FFunctionCompilationScope(URigVMCompiler* InCompiler, const URigVMLibraryNode* InLibraryNode) : Compiler(InCompiler), LibraryNode(InLibraryNode) { InCompiler->FunctionCompilationStack.Add(InLibraryNode); } ~FFunctionCompilationScope() { Compiler->FunctionCompilationStack.Remove(LibraryNode); } private: URigVMCompiler* Compiler; const URigVMLibraryNode* LibraryNode; };