2014-12-07 19:09:38 -05:00
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
2014-03-14 14:13:41 -04:00
2015-03-30 14:10:13 -04:00
# include "BlueprintCompilerCppBackendModulePrivatePCH.h"
# include "BlueprintCompilerCppBackend.h"
# include "BlueprintCompilerCppBackendUtils.h"
2014-03-14 14:13:41 -04:00
2015-03-30 14:10:13 -04:00
FString FBlueprintCompilerCppBackend : : TermToText ( const FBPTerminal * Term , const UProperty * CoerceProperty )
2014-03-14 14:13:41 -04:00
{
2015-03-30 14:10:13 -04:00
const FString PSC_Self ( TEXT ( " self " ) ) ;
2014-03-14 14:13:41 -04:00
if ( Term - > bIsLiteral )
{
//@TODO: Must have a coercion type if it's a literal, because the symbol table isn't plumbed in here and the literals don't carry type information either, yay!
2014-09-18 09:33:08 -04:00
ensure ( CoerceProperty ) ;
2014-03-14 14:13:41 -04:00
if ( CoerceProperty - > IsA ( UStrProperty : : StaticClass ( ) ) )
{
return FString : : Printf ( TEXT ( " TEXT( \" %s \" ) " ) , * ( Term - > Name ) ) ;
}
2015-03-30 14:10:13 -04:00
else if ( CoerceProperty - > IsA ( UTextProperty : : StaticClass ( ) ) )
2014-10-27 07:57:32 -04:00
{
return FString : : Printf ( TEXT ( " FText::FromString(TEXT( \" %s \" )) " ) , * ( Term - > Name ) ) ;
}
2014-03-14 14:13:41 -04:00
else if ( CoerceProperty - > IsA ( UFloatProperty : : StaticClass ( ) ) )
{
float Value = FCString : : Atof ( * ( Term - > Name ) ) ;
return FString : : Printf ( TEXT ( " %f " ) , Value ) ;
}
else if ( CoerceProperty - > IsA ( UIntProperty : : StaticClass ( ) ) )
{
int32 Value = FCString : : Atoi ( * ( Term - > Name ) ) ;
return FString : : Printf ( TEXT ( " %d " ) , Value ) ;
}
2014-09-23 13:19:42 -04:00
else if ( auto ByteProperty = Cast < const UByteProperty > ( CoerceProperty ) )
2014-03-14 14:13:41 -04:00
{
// The PinSubCategoryObject check is to allow enum literals communicate with byte properties as literals
if ( ByteProperty - > Enum ! = NULL | |
( NULL ! = Cast < UEnum > ( Term - > Type . PinSubCategoryObject . Get ( ) ) ) )
{
return Term - > Name ;
}
else
{
uint8 Value = FCString : : Atoi ( * ( Term - > Name ) ) ;
return FString : : Printf ( TEXT ( " %u " ) , Value ) ;
}
}
2014-09-23 13:19:42 -04:00
else if ( auto BoolProperty = Cast < const UBoolProperty > ( CoerceProperty ) )
2014-03-14 14:13:41 -04:00
{
bool bValue = Term - > Name . ToBool ( ) ;
2014-09-30 11:36:10 -04:00
return bValue ? TEXT ( " true " ) : TEXT ( " false " ) ;
2014-03-14 14:13:41 -04:00
}
2014-09-23 13:19:42 -04:00
else if ( auto NameProperty = Cast < const UNameProperty > ( CoerceProperty ) )
2014-03-14 14:13:41 -04:00
{
FName LiteralName ( * ( Term - > Name ) ) ;
2014-09-30 11:36:10 -04:00
return FString : : Printf ( TEXT ( " FName(TEXT( \" %s \" )) " ) , * ( LiteralName . ToString ( ) ) ) ;
2014-03-14 14:13:41 -04:00
}
2014-09-23 13:19:42 -04:00
else if ( auto StructProperty = Cast < const UStructProperty > ( CoerceProperty ) )
2014-03-14 14:13:41 -04:00
{
if ( StructProperty - > Struct = = VectorStruct )
{
FVector Vect = FVector : : ZeroVector ;
FDefaultValueHelper : : ParseVector ( Term - > Name , /*out*/ Vect ) ;
return FString : : Printf ( TEXT ( " FVector(%f,%f,%f) " ) , Vect . X , Vect . Y , Vect . Z ) ;
}
else if ( StructProperty - > Struct = = RotatorStruct )
{
FRotator Rot = FRotator : : ZeroRotator ;
FDefaultValueHelper : : ParseRotator ( Term - > Name , /*out*/ Rot ) ;
return FString : : Printf ( TEXT ( " FRotator(%f,%f,%f) " ) , Rot . Pitch , Rot . Yaw , Rot . Roll ) ;
}
else if ( StructProperty - > Struct = = TransformStruct )
{
FTransform Trans = FTransform : : Identity ;
2015-03-30 14:10:13 -04:00
Trans . InitFromString ( Term - > Name ) ;
2014-03-14 14:13:41 -04:00
const FQuat Rot = Trans . GetRotation ( ) ;
const FVector Translation = Trans . GetTranslation ( ) ;
const FVector Scale = Trans . GetScale3D ( ) ;
return FString : : Printf ( TEXT ( " FTransform( FQuat(%f,%f,%f,%f), FVector(%f,%f,%f), FVector(%f,%f,%f) ) " ) ,
Rot . X , Rot . Y , Rot . Z , Rot . W , Translation . X , Translation . Y , Translation . Z , Scale . X , Scale . Y , Scale . Z ) ;
}
2014-09-18 09:33:08 -04:00
else if ( StructProperty - > Struct = = LinearColorStruct )
{
FLinearColor LinearColor ;
LinearColor . InitFromString ( Term - > Name ) ;
return FString : : Printf ( TEXT ( " FLinearColor(%f,%f,%f,%f) " ) , LinearColor . R , LinearColor . G , LinearColor . B , LinearColor . A ) ;
}
2014-03-14 14:13:41 -04:00
else
{
//@todo: This needs to be more robust, since import text isn't really proper for struct construction.
return FString ( TEXT ( " F " ) ) + StructProperty - > Struct - > GetName ( ) + Term - > Name ;
}
}
2014-09-23 13:19:42 -04:00
else if ( auto ClassProperty = Cast < const UClassProperty > ( CoerceProperty ) )
2014-03-14 14:13:41 -04:00
{
2014-09-30 05:04:55 -04:00
if ( auto FoundClass = Cast < const UClass > ( Term - > ObjectLiteral ) )
{
2014-10-13 07:05:57 -04:00
return FString : : Printf ( TEXT ( " %s%s::StaticClass() " ) , FoundClass - > GetPrefixCPP ( ) , * FoundClass - > GetName ( ) ) ;
2014-09-30 05:04:55 -04:00
}
return FString ( TEXT ( " NULL " ) ) ;
2014-03-14 14:13:41 -04:00
}
else if ( CoerceProperty - > IsA ( UDelegateProperty : : StaticClass ( ) ) )
{
//@TODO: K2 Delegate Support: Won't compile, there isn't an operator= that does what we want here, it should be a proper call to BindDynamic instead!
if ( Term - > Name = = TEXT ( " " ) )
{
return TEXT ( " NULL " ) ;
}
else
{
return FString : : Printf ( TEXT ( " BindDynamic(this, &%s::%s) " ) , * CppClassName , * ( Term - > Name ) ) ;
}
}
else if ( CoerceProperty - > IsA ( UObjectPropertyBase : : StaticClass ( ) ) )
{
2015-03-30 14:10:13 -04:00
if ( Term - > Type . PinSubCategory = = PSC_Self )
2014-03-14 14:13:41 -04:00
{
return TEXT ( " this " ) ;
}
else if ( Term - > ObjectLiteral )
{
2014-09-23 13:19:42 -04:00
if ( auto LiteralClass = Cast < const UClass > ( Term - > ObjectLiteral ) )
2014-03-14 14:13:41 -04:00
{
2014-10-13 07:05:57 -04:00
return FString : : Printf ( TEXT ( " %s%s::StaticClass() " ) , LiteralClass - > GetPrefixCPP ( ) , * LiteralClass - > GetName ( ) ) ;
2014-03-14 14:13:41 -04:00
}
else
{
2014-09-23 13:19:42 -04:00
auto ObjectCoerceProperty = CastChecked < const UObjectPropertyBase > ( CoerceProperty ) ;
2014-09-18 09:33:08 -04:00
UClass * FoundClass = ObjectCoerceProperty ? ObjectCoerceProperty - > PropertyClass : NULL ;
FString ClassString = FoundClass ? ( FString ( FoundClass - > GetPrefixCPP ( ) ) + FoundClass - > GetName ( ) ) : TEXT ( " UObject " ) ;
return FString : : Printf ( TEXT ( " FindObject<%s>(ANY_PACKAGE, TEXT( \" %s \" )) " ) , * ClassString , * ( Term - > ObjectLiteral - > GetPathName ( ) ) ) ;
2014-03-14 14:13:41 -04:00
}
}
else
{
return FString ( TEXT ( " NULL " ) ) ;
}
}
else if ( CoerceProperty - > IsA ( UInterfaceProperty : : StaticClass ( ) ) )
{
2015-03-30 14:10:13 -04:00
if ( Term - > Type . PinSubCategory = = PSC_Self )
2014-03-14 14:13:41 -04:00
{
return TEXT ( " this " ) ;
}
2015-03-30 14:10:13 -04:00
else
2014-03-14 14:13:41 -04:00
{
ensureMsg ( false , TEXT ( " It is not possible to express this interface property as a literal value! " ) ) ;
return Term - > Name ;
}
}
else
2015-03-30 14:10:13 -04:00
// else if (CoerceProperty->IsA(UMulticastDelegateProperty::StaticClass()))
// Cannot assign a literal to a multicast delegate; it should be added instead of assigned
2014-03-14 14:13:41 -04:00
{
ensureMsg ( false , TEXT ( " It is not possible to express this type as a literal value! " ) ) ;
return Term - > Name ;
}
}
else
{
FString Prefix ( TEXT ( " " ) ) ;
2015-03-30 14:10:13 -04:00
if ( ( Term - > Context ! = NULL ) & & ( Term - > Context - > Name ! = PSC_Self ) )
2014-03-14 14:13:41 -04:00
{
Prefix = TermToText ( Term - > Context ) ;
if ( Term - > Context - > bIsStructContext )
{
Prefix + = TEXT ( " . " ) ;
}
else
{
Prefix + = TEXT ( " -> " ) ;
}
}
Prefix + = Term - > Name ;
return Prefix ;
}
}
2015-03-30 14:10:13 -04:00
FString FBlueprintCompilerCppBackend : : LatentFunctionInfoTermToText ( FBPTerminal * Term , FBlueprintCompiledStatement * TargetLabel )
2014-03-14 14:13:41 -04:00
{
check ( LatentInfoStruct ) ;
// Find the term name we need to fixup
FString FixupTermName ;
for ( UProperty * Prop = LatentInfoStruct - > PropertyLink ; Prop ; Prop = Prop - > PropertyLinkNext )
{
2015-03-30 14:10:13 -04:00
static const FName NeedsLatentFixup ( TEXT ( " NeedsLatentFixup " ) ) ;
if ( Prop - > GetBoolMetaData ( NeedsLatentFixup ) )
2014-03-14 14:13:41 -04:00
{
FixupTermName = Prop - > GetName ( ) ;
break ;
}
}
check ( ! FixupTermName . IsEmpty ( ) ) ;
FString StructValues = Term - > Name ;
// Index 0 is always the ubergraph
const int32 TargetStateIndex = StateMapPerFunction [ 0 ] . StatementToStateIndex ( TargetLabel ) ;
const int32 LinkageTermStartIdx = StructValues . Find ( FixupTermName ) ;
check ( LinkageTermStartIdx ! = INDEX_NONE ) ;
StructValues = StructValues . Replace ( TEXT ( " -1 " ) , * FString : : FromInt ( TargetStateIndex ) ) ;
return FString ( TEXT ( " F " ) ) + LatentInfoStruct - > GetName ( ) + StructValues ;
}
2015-03-30 14:10:13 -04:00
void FBlueprintCompilerCppBackend : : EmitClassProperties ( FStringOutputDevice & Target , UClass * SourceClass )
2014-03-14 14:13:41 -04:00
{
// Emit class variables
for ( TFieldIterator < UProperty > It ( SourceClass , EFieldIteratorFlags : : ExcludeSuper ) ; It ; + + It )
{
UProperty * Property = * It ;
2014-09-18 09:33:08 -04:00
check ( Property ) ;
2014-03-14 14:13:41 -04:00
2014-09-18 09:33:08 -04:00
Emit ( Header , TEXT ( " \n \t UPROPERTY( " ) ) ;
{
2014-09-30 05:04:55 -04:00
TArray < FString > Tags = FEmitHelper : : ProperyFlagsToTags ( Property - > PropertyFlags ) ;
Tags . Emplace ( FEmitHelper : : HandleRepNotifyFunc ( Property ) ) ;
2014-09-30 11:36:10 -04:00
Tags . Emplace ( FEmitHelper : : HandleMetaData ( Property , false ) ) ;
2014-09-18 09:33:08 -04:00
Tags . Remove ( FString ( ) ) ;
FString AllTags ;
2014-09-30 05:04:55 -04:00
FEmitHelper : : ArrayToString ( Tags , AllTags , TEXT ( " , " ) ) ;
2014-09-18 09:33:08 -04:00
Emit ( Header , * AllTags ) ;
}
Emit ( Header , TEXT ( " ) \n " ) ) ;
2014-03-14 14:13:41 -04:00
Emit ( Header , TEXT ( " \t " ) ) ;
2014-09-30 05:04:55 -04:00
Property - > ExportCppDeclaration ( Target , EExportedDeclaration : : Member , NULL , EPropertyExportCPPFlags : : CPPF_CustomTypeName ) ;
2014-03-14 14:13:41 -04:00
Emit ( Header , TEXT ( " ; \n " ) ) ;
}
}
2015-03-30 14:10:13 -04:00
void FBlueprintCompilerCppBackend : : GenerateCodeFromClass ( UClass * SourceClass , FString NewClassName , TIndirectArray < FKismetFunctionContext > & Functions , bool bGenerateStubsOnly )
2014-03-14 14:13:41 -04:00
{
2015-03-23 14:35:43 -04:00
auto CleanCppClassName = NewClassName . IsEmpty ( ) ? SourceClass - > GetName ( ) : NewClassName ;
CppClassName = FString ( SourceClass - > GetPrefixCPP ( ) ) + CleanCppClassName ;
2014-03-14 14:13:41 -04:00
UClass * SuperClass = SourceClass - > GetSuperClass ( ) ;
2014-09-18 09:33:08 -04:00
Emit ( Header , TEXT ( " #pragma once \n \n " ) ) ;
2015-03-23 14:35:43 -04:00
Emit ( Header , * FString : : Printf ( TEXT ( " #include \" %s.generated.h \" \n \n " ) , * CleanCppClassName ) ) ;
2014-09-30 05:04:55 -04:00
// MC DELEGATE DECLARATION
{
auto DelegateDeclarations = FEmitHelper : : EmitMulticastDelegateDeclarations ( SourceClass ) ;
FString AllDeclarations ;
FEmitHelper : : ArrayToString ( DelegateDeclarations , AllDeclarations , TEXT ( " ; \n " ) ) ;
if ( DelegateDeclarations . Num ( ) )
{
Emit ( Header , * AllDeclarations ) ;
Emit ( Header , TEXT ( " ; \n " ) ) ;
}
}
// GATHER ALL SC DELEGATES
{
2014-09-30 11:36:10 -04:00
TArray < UDelegateProperty * > Delegates ;
for ( TFieldIterator < UDelegateProperty > It ( SourceClass , EFieldIteratorFlags : : ExcludeSuper ) ; It ; + + It )
2014-09-30 05:04:55 -04:00
{
Delegates . Add ( * It ) ;
}
for ( auto & FuncContext : Functions )
{
2014-09-30 11:36:10 -04:00
for ( TFieldIterator < UDelegateProperty > It ( FuncContext . Function , EFieldIteratorFlags : : ExcludeSuper ) ; It ; + + It )
2014-09-30 05:04:55 -04:00
{
Delegates . Add ( * It ) ;
}
}
auto DelegateDeclarations = FEmitHelper : : EmitSinglecastDelegateDeclarations ( Delegates ) ;
FString AllDeclarations ;
FEmitHelper : : ArrayToString ( DelegateDeclarations , AllDeclarations , TEXT ( " ; \n " ) ) ;
if ( DelegateDeclarations . Num ( ) )
{
Emit ( Header , * AllDeclarations ) ;
Emit ( Header , TEXT ( " ; \n " ) ) ;
}
}
2014-09-18 09:33:08 -04:00
Emit ( Header , TEXT ( " UCLASS(Blueprintable) \n " ) ) ;
2014-03-14 14:13:41 -04:00
Emit ( Header ,
* FString : : Printf ( TEXT ( " class %s : public %s%s \n " ) , * CppClassName , SuperClass - > GetPrefixCPP ( ) , * SuperClass - > GetName ( ) ) ) ;
Emit ( Header ,
TEXT ( " { \n " )
TEXT ( " public: \n " ) ) ;
2015-03-17 06:17:32 -04:00
Emit ( Header , * FString : : Printf ( TEXT ( " \t GENERATED_UCLASS_BODY() \n " ) ) ) ;
2014-03-14 14:13:41 -04:00
EmitClassProperties ( Header , SourceClass ) ;
// Create the state map
for ( int32 i = 0 ; i < Functions . Num ( ) ; + + i )
{
StateMapPerFunction . Add ( FFunctionLabelInfo ( ) ) ;
FunctionIndexMap . Add ( & Functions [ i ] , i ) ;
}
// Emit function declarations and definitions (writes to header and body simultaneously)
if ( Functions . Num ( ) > 0 )
{
Emit ( Header , TEXT ( " \n " ) ) ;
}
2015-03-30 14:10:13 -04:00
TArray < FString > PersistentHeaders ;
PersistentHeaders . Add ( FString ( FApp : : GetGameName ( ) ) + TEXT ( " .h " ) ) ;
PersistentHeaders . Add ( CleanCppClassName + TEXT ( " .h " ) ) ;
PersistentHeaders . Add ( TEXT ( " GeneratedCodeHelpers.h " ) ) ;
Emit ( Body , * FEmitHelper : : GatherHeadersToInclude ( SourceClass , PersistentHeaders ) ) ;
2015-03-23 14:35:43 -04:00
2015-03-17 06:17:32 -04:00
//constructor
Emit ( Body , * FString : : Printf (
TEXT ( " %s::%s(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) {} \n \n " ) ,
* CppClassName , * CppClassName ) ) ;
2014-03-14 14:13:41 -04:00
for ( int32 i = 0 ; i < Functions . Num ( ) ; + + i )
{
if ( Functions [ i ] . IsValid ( ) )
{
ConstructFunction ( Functions [ i ] , bGenerateStubsOnly ) ;
}
}
Emit ( Header , TEXT ( " }; \n \n " ) ) ;
2014-10-27 07:57:32 -04:00
2015-03-23 14:35:43 -04:00
Emit ( Body , * FEmitHelper : : EmitLifetimeReplicatedPropsImpl ( SourceClass , CppClassName , TEXT ( " " ) ) ) ;
2014-03-14 14:13:41 -04:00
}
2015-03-30 14:10:13 -04:00
void FBlueprintCompilerCppBackend : : EmitCallDelegateStatment ( FKismetFunctionContext & FunctionContext , FBlueprintCompiledStatement & Statement )
2014-03-14 14:13:41 -04:00
{
2014-09-30 05:04:55 -04:00
check ( Statement . FunctionContext & & Statement . FunctionContext - > AssociatedVarProperty ) ;
FSafeContextScopedEmmitter SafeContextScope ( Body , Statement . FunctionContext - > Context , * this , TEXT ( " \t \t \t " ) ) ;
Emit ( Body , TEXT ( " \t \t \t " ) ) ;
Emit ( Body , * SafeContextScope . GetAdditionalIndent ( ) ) ;
Emit ( Body , * FString : : Printf ( TEXT ( " %s.Broadcast( " ) , * TermToText ( Statement . FunctionContext ) ) ) ;
2014-03-14 14:13:41 -04:00
int32 NumParams = 0 ;
for ( TFieldIterator < UProperty > PropIt ( Statement . FunctionToCall ) ; PropIt & & ( PropIt - > PropertyFlags & CPF_Parm ) ; + + PropIt )
{
UProperty * FuncParamProperty = * PropIt ;
if ( ! FuncParamProperty - > HasAnyPropertyFlags ( CPF_ReturnParm ) )
{
if ( NumParams > 0 )
{
Emit ( Body , TEXT ( " , " ) ) ;
}
FString VarName ;
FBPTerminal * Term = Statement . RHS [ NumParams ] ;
ensure ( Term ! = NULL ) ;
// See if this is a hidden array param term, which needs to be fixed up with the final generated UArrayProperty
2015-03-30 14:10:13 -04:00
if ( FBPTerminal * * ArrayParmTerm = Statement . ArrayCoersionTermMap . Find ( Term ) )
2014-03-14 14:13:41 -04:00
{
Term - > ObjectLiteral = ( * ArrayParmTerm ) - > AssociatedVarProperty ;
}
2015-03-30 14:10:13 -04:00
if ( ( Statement . TargetLabel ! = NULL ) & & ( Statement . UbergraphCallIndex = = NumParams ) )
2014-03-14 14:13:41 -04:00
{
// The target label will only ever be set on a call function when calling into the Ubergraph or
// on a latent function that will later call into the ubergraph, either of which requires a patchup
UStructProperty * StructProp = Cast < UStructProperty > ( FuncParamProperty ) ;
2015-03-30 14:10:13 -04:00
if ( StructProp & & StructProp - > Struct = = LatentInfoStruct )
2014-03-14 14:13:41 -04:00
{
// Latent function info case
VarName = LatentFunctionInfoTermToText ( Term , Statement . TargetLabel ) ;
}
else
{
// Ubergraph entry point case
VarName = FString : : FromInt ( StateMapPerFunction [ 0 ] . StatementToStateIndex ( Statement . TargetLabel ) ) ;
}
}
else
{
// Emit a normal parameter term
VarName = TermToText ( Term , FuncParamProperty ) ;
}
if ( FuncParamProperty - > HasAnyPropertyFlags ( CPF_OutParm ) )
{
Emit ( Body , TEXT ( " /*out*/ " ) ) ;
}
Emit ( Body , * VarName ) ;
NumParams + + ;
}
}
Emit ( Body , TEXT ( " ); \n " ) ) ;
}
2015-03-30 14:10:13 -04:00
void FBlueprintCompilerCppBackend : : EmitCallStatment ( FKismetFunctionContext & FunctionContext , FBlueprintCompiledStatement & Statement )
2014-03-14 14:13:41 -04:00
{
2015-03-30 14:10:13 -04:00
const bool bCallOnDifferentObject = ( Statement . FunctionContext ! = NULL ) & & ( Statement . FunctionContext - > Name ! = TEXT ( " self " ) ) ;
2014-09-30 05:04:55 -04:00
const bool bStaticCall = Statement . FunctionToCall - > HasAnyFunctionFlags ( FUNC_Static ) ;
const bool bUseSafeContext = bCallOnDifferentObject & & ! bStaticCall ;
FSafeContextScopedEmmitter SafeContextScope ( Body , bUseSafeContext ? Statement . FunctionContext : NULL , * this , TEXT ( " \t \t \t " ) ) ;
2014-03-14 14:13:41 -04:00
Emit ( Body , TEXT ( " \t \t \t " ) ) ;
2014-09-30 05:04:55 -04:00
Emit ( Body , * SafeContextScope . GetAdditionalIndent ( ) ) ;
2014-03-14 14:13:41 -04:00
// Handle the return value of the function being called
UProperty * FuncToCallReturnProperty = Statement . FunctionToCall - > GetReturnProperty ( ) ;
if ( FuncToCallReturnProperty ! = NULL )
{
FBPTerminal * Term = Statement . LHS ;
ensure ( Term ! = NULL ) ;
FString ReturnVarName = TermToText ( Term ) ;
Emit ( Body , * FString : : Printf ( TEXT ( " %s = " ) , * ReturnVarName ) ) ;
}
// Emit object to call the method on
2014-09-30 05:04:55 -04:00
if ( bCallOnDifferentObject ) //@TODO: Badness, could be a self reference wired to another instance!
2014-03-14 14:13:41 -04:00
{
2014-09-30 05:04:55 -04:00
if ( bStaticCall )
2014-03-14 14:13:41 -04:00
{
2014-09-18 09:33:08 -04:00
const bool bIsCustomThunk = Statement . FunctionToCall - > HasMetaData ( TEXT ( " CustomStructureParam " ) ) | | Statement . FunctionToCall - > HasMetaData ( TEXT ( " ArrayParm " ) ) ;
FString FullFunctionNamePrefix = bIsCustomThunk
? TEXT ( " FCustomThunkTemplates:: " )
: FString : : Printf ( TEXT ( " U%s:: " ) , * Statement . FunctionToCall - > GetOuter ( ) - > GetName ( ) ) ;
Emit ( Body , * FullFunctionNamePrefix ) ; //@TODO: Assuming U prefix but could be A
2014-03-14 14:13:41 -04:00
}
else
{
Emit ( Body , * FString : : Printf ( TEXT ( " %s-> " ) , * TermToText ( Statement . FunctionContext , ( UProperty * ) ( GetDefault < UObjectProperty > ( ) ) ) ) ) ;
}
}
// Emit method name
FString FunctionNameToCall ;
Statement . FunctionToCall - > GetName ( FunctionNameToCall ) ;
2015-03-30 14:10:13 -04:00
if ( Statement . bIsParentContext )
2014-03-14 14:13:41 -04:00
{
2014-10-27 07:57:32 -04:00
FunctionNameToCall = TEXT ( " Super:: " ) + FunctionNameToCall ;
2014-03-14 14:13:41 -04:00
}
Emit ( Body , * FString : : Printf ( TEXT ( " %s " ) , * FunctionNameToCall ) ) ;
// Emit method parameter list
Emit ( Body , TEXT ( " ( " ) ) ;
{
int32 NumParams = 0 ;
for ( TFieldIterator < UProperty > PropIt ( Statement . FunctionToCall ) ; PropIt & & ( PropIt - > PropertyFlags & CPF_Parm ) ; + + PropIt )
{
UProperty * FuncParamProperty = * PropIt ;
if ( ! FuncParamProperty - > HasAnyPropertyFlags ( CPF_ReturnParm ) )
{
if ( NumParams > 0 )
{
Emit ( Body , TEXT ( " , " ) ) ;
}
FString VarName ;
FBPTerminal * Term = Statement . RHS [ NumParams ] ;
ensure ( Term ! = NULL ) ;
// See if this is a hidden array param term, which needs to be fixed up with the final generated UArrayProperty
2015-03-30 14:10:13 -04:00
if ( FBPTerminal * * ArrayParmTerm = Statement . ArrayCoersionTermMap . Find ( Term ) )
2014-03-14 14:13:41 -04:00
{
Term - > ObjectLiteral = ( * ArrayParmTerm ) - > AssociatedVarProperty ;
}
2015-03-30 14:10:13 -04:00
if ( ( Statement . TargetLabel ! = NULL ) & & ( Statement . UbergraphCallIndex = = NumParams ) )
2014-03-14 14:13:41 -04:00
{
// The target label will only ever be set on a call function when calling into the Ubergraph or
// on a latent function that will later call into the ubergraph, either of which requires a patchup
UStructProperty * StructProp = Cast < UStructProperty > ( FuncParamProperty ) ;
2015-03-30 14:10:13 -04:00
if ( StructProp & & StructProp - > Struct = = LatentInfoStruct )
2014-03-14 14:13:41 -04:00
{
// Latent function info case
VarName = LatentFunctionInfoTermToText ( Term , Statement . TargetLabel ) ;
}
else
{
// Ubergraph entry point case
VarName = FString : : FromInt ( StateMapPerFunction [ 0 ] . StatementToStateIndex ( Statement . TargetLabel ) ) ;
}
}
else
{
// Emit a normal parameter term
VarName = TermToText ( Term , FuncParamProperty ) ;
}
if ( FuncParamProperty - > HasAnyPropertyFlags ( CPF_OutParm ) )
{
Emit ( Body , TEXT ( " /*out*/ " ) ) ;
}
Emit ( Body , * VarName ) ;
NumParams + + ;
}
}
}
Emit ( Body , TEXT ( " ); \n " ) ) ;
}
2015-03-30 14:10:13 -04:00
void FBlueprintCompilerCppBackend : : EmitAssignmentStatment ( FKismetFunctionContext & FunctionContext , FBlueprintCompiledStatement & Statement )
2014-03-14 14:13:41 -04:00
{
2014-09-30 05:04:55 -04:00
FString DestinationExpression = TermToText ( Statement . LHS ) ;
FString SourceExpression = TermToText ( Statement . RHS [ 0 ] , Statement . LHS - > AssociatedVarProperty ) ;
2014-03-14 14:13:41 -04:00
2014-09-30 05:04:55 -04:00
FSafeContextScopedEmmitter SafeContextScope ( Body , Statement . LHS - > Context , * this , TEXT ( " \t \t \t " ) ) ;
2014-03-14 14:13:41 -04:00
// Emit the assignment statement
2014-09-30 05:04:55 -04:00
Emit ( Body , TEXT ( " \t \t \t " ) ) ;
Emit ( Body , * SafeContextScope . GetAdditionalIndent ( ) ) ;
Emit ( Body , * FString : : Printf ( TEXT ( " %s = %s; \n " ) , * DestinationExpression , * SourceExpression ) ) ;
2014-03-14 14:13:41 -04:00
}
2015-03-30 14:10:13 -04:00
void FBlueprintCompilerCppBackend : : EmitCastObjToInterfaceStatement ( FKismetFunctionContext & FunctionContext , FBlueprintCompiledStatement & Statement )
2014-03-14 14:13:41 -04:00
{
FString InterfaceClass = TermToText ( Statement . RHS [ 0 ] , ( UProperty * ) ( GetDefault < UClassProperty > ( ) ) ) ;
FString ObjectValue = TermToText ( Statement . RHS [ 1 ] , ( UProperty * ) ( GetDefault < UObjectProperty > ( ) ) ) ;
FString InterfaceValue = TermToText ( Statement . LHS , ( UProperty * ) ( GetDefault < UObjectProperty > ( ) ) ) ;
2014-09-30 05:04:55 -04:00
Emit ( Body , * FString : : Printf ( TEXT ( " \t \t \t if ( IsValid(%s) && %s->GetClass()->ImplementsInterface(%s) ) \n " ) , * ObjectValue , * ObjectValue , * InterfaceClass ) ) ;
2014-03-14 14:13:41 -04:00
Emit ( Body , * FString : : Printf ( TEXT ( " \t \t \t { \n " ) ) ) ;
Emit ( Body , * FString : : Printf ( TEXT ( " \t \t \t \t %s.SetObject(%s); \n " ) , * InterfaceValue , * ObjectValue ) ) ;
Emit ( Body , * FString : : Printf ( TEXT ( " \t \t \t \t void* IAddress = %s->GetInterfaceAddress(%s); \n " ) , * ObjectValue , * InterfaceClass ) ) ;
Emit ( Body , * FString : : Printf ( TEXT ( " \t \t \t \t %s.SetInterface(IAddress); \n " ) , * InterfaceValue ) ) ;
Emit ( Body , * FString : : Printf ( TEXT ( " \t \t \t } \n " ) ) ) ;
Emit ( Body , * FString : : Printf ( TEXT ( " \t \t \t else \n " ) ) ) ;
Emit ( Body , * FString : : Printf ( TEXT ( " \t \t \t { \n " ) ) ) ;
Emit ( Body , * FString : : Printf ( TEXT ( " \t \t \t \t %s.SetObject(NULL); \n " ) , * InterfaceValue ) ) ;
Emit ( Body , * FString : : Printf ( TEXT ( " \t \t \t } \n " ) ) ) ;
}
2015-03-30 14:10:13 -04:00
void FBlueprintCompilerCppBackend : : EmitCastBetweenInterfacesStatement ( FKismetFunctionContext & FunctionContext , FBlueprintCompiledStatement & Statement )
2014-04-02 18:09:23 -04:00
{
2015-03-30 14:10:13 -04:00
FString ClassToCastTo = TermToText ( Statement . RHS [ 0 ] , ( UProperty * ) ( GetDefault < UClassProperty > ( ) ) ) ;
FString InputInterface = TermToText ( Statement . RHS [ 1 ] , ( UProperty * ) ( GetDefault < UInterfaceProperty > ( ) ) ) ;
2014-04-02 18:09:23 -04:00
FString ResultInterface = TermToText ( Statement . LHS , ( UProperty * ) ( GetDefault < UInterfaceProperty > ( ) ) ) ;
FString InputObject = FString : : Printf ( TEXT ( " %s.GetObjectRef() " ) , * InputInterface ) ;
Emit ( Body , * FString : : Printf ( TEXT ( " \t \t \t if ( %s && %s->GetClass()->IsChildOf(%s) ) \n " ) , * InputObject , * InputObject , * ClassToCastTo ) ) ;
Emit ( Body , * FString : : Printf ( TEXT ( " \t \t \t { \n " ) ) ) ;
Emit ( Body , * FString : : Printf ( TEXT ( " \t \t \t \t %s.SetObject(%s); \n " ) , * ResultInterface , * InputObject ) ) ;
Emit ( Body , * FString : : Printf ( TEXT ( " \t \t \t \t void* IAddress = %s->GetInterfaceAddress(%s); \n " ) , * InputObject , * ClassToCastTo ) ) ;
Emit ( Body , * FString : : Printf ( TEXT ( " \t \t \t \t %s.SetInterface(IAddress); \n " ) , * ResultInterface ) ) ;
Emit ( Body , * FString : : Printf ( TEXT ( " \t \t \t } \n " ) ) ) ;
Emit ( Body , * FString : : Printf ( TEXT ( " \t \t \t else \n " ) ) ) ;
Emit ( Body , * FString : : Printf ( TEXT ( " \t \t \t { \n " ) ) ) ;
Emit ( Body , * FString : : Printf ( TEXT ( " \t \t \t \t %s.SetObject(NULL); \n " ) , * ResultInterface ) ) ;
Emit ( Body , * FString : : Printf ( TEXT ( " \t \t \t } \n " ) ) ) ;
}
2015-03-30 14:10:13 -04:00
void FBlueprintCompilerCppBackend : : EmitCastInterfaceToObjStatement ( FKismetFunctionContext & FunctionContext , FBlueprintCompiledStatement & Statement )
2014-10-23 12:15:59 -04:00
{
FString ClassToCastTo = TermToText ( Statement . RHS [ 0 ] , ( UProperty * ) ( GetDefault < UClassProperty > ( ) ) ) ;
FString InputInterface = TermToText ( Statement . RHS [ 1 ] , ( UProperty * ) ( GetDefault < UInterfaceProperty > ( ) ) ) ;
FString ResultObject = TermToText ( Statement . LHS , ( UProperty * ) ( GetDefault < UInterfaceProperty > ( ) ) ) ;
FString InputObject = FString : : Printf ( TEXT ( " %s.GetObjectRef() " ) , * InputInterface ) ;
2015-03-30 14:10:13 -04:00
2014-10-23 12:15:59 -04:00
Emit ( Body , * FString : : Printf ( TEXT ( " \t \t \t %s = Cast<%s>(%s); \n " ) ,
* ResultObject , * ClassToCastTo , * InputObject ) ) ;
}
2015-03-30 14:10:13 -04:00
void FBlueprintCompilerCppBackend : : EmitDynamicCastStatement ( FKismetFunctionContext & FunctionContext , FBlueprintCompiledStatement & Statement )
2014-03-14 14:13:41 -04:00
{
FString TargetClass = TermToText ( Statement . RHS [ 0 ] , ( UProperty * ) ( GetDefault < UClassProperty > ( ) ) ) ;
FString ObjectValue = TermToText ( Statement . RHS [ 1 ] , ( UProperty * ) ( GetDefault < UObjectProperty > ( ) ) ) ;
FString CastedValue = TermToText ( Statement . LHS , ( UProperty * ) ( GetDefault < UObjectProperty > ( ) ) ) ;
2014-09-15 06:09:48 -04:00
Emit ( Body , * FString : : Printf ( TEXT ( " \t \t \t %s = Cast<%s>(%s); \n " ) ,
2014-03-14 14:13:41 -04:00
* CastedValue , * TargetClass , * ObjectValue ) ) ;
}
2015-03-30 14:10:13 -04:00
void FBlueprintCompilerCppBackend : : EmitMetaCastStatement ( FKismetFunctionContext & FunctionContext , FBlueprintCompiledStatement & Statement )
2014-09-15 06:09:48 -04:00
{
2015-03-30 14:10:13 -04:00
FString DesiredClass = TermToText ( Statement . RHS [ 0 ] , ( UProperty * ) ( GetDefault < UClassProperty > ( ) ) ) ;
FString SourceClass = TermToText ( Statement . RHS [ 1 ] , ( UProperty * ) ( GetDefault < UClassProperty > ( ) ) ) ;
FString Destination = TermToText ( Statement . LHS , ( UProperty * ) ( GetDefault < UClassProperty > ( ) ) ) ;
2014-09-15 06:09:48 -04:00
2014-09-18 09:33:08 -04:00
Emit ( Body , * FString : : Printf ( TEXT ( " \t \t \t %s = DynamicMetaCast(%s, %s); \n " ) ,
* Destination , * DesiredClass , * SourceClass ) ) ;
2014-09-15 06:09:48 -04:00
}
2015-03-30 14:10:13 -04:00
void FBlueprintCompilerCppBackend : : EmitObjectToBoolStatement ( FKismetFunctionContext & FunctionContext , FBlueprintCompiledStatement & Statement )
2014-03-14 14:13:41 -04:00
{
FString ObjectTarget = TermToText ( Statement . RHS [ 0 ] ) ;
FString DestinationExpression = TermToText ( Statement . LHS ) ;
Emit ( Body , * FString : : Printf ( TEXT ( " \t \t \t %s = (%s != NULL); \n " ) , * DestinationExpression , * ObjectTarget ) ) ;
}
2015-03-30 14:10:13 -04:00
void FBlueprintCompilerCppBackend : : EmitAddMulticastDelegateStatement ( FKismetFunctionContext & FunctionContext , FBlueprintCompiledStatement & Statement )
2014-03-14 14:13:41 -04:00
{
2014-09-30 05:04:55 -04:00
check ( Statement . LHS & & Statement . LHS - > AssociatedVarProperty ) ;
FSafeContextScopedEmmitter SafeContextScope ( Body , Statement . LHS - > Context , * this , TEXT ( " \t \t \t " ) ) ;
Emit ( Body , TEXT ( " \t \t \t " ) ) ;
Emit ( Body , * SafeContextScope . GetAdditionalIndent ( ) ) ;
2014-03-14 14:13:41 -04:00
const FString Delegate = TermToText ( Statement . LHS ) ;
const FString DelegateToAdd = TermToText ( Statement . RHS [ 0 ] ) ;
2014-09-30 05:04:55 -04:00
Emit ( Body , * FString : : Printf ( TEXT ( " %s.Add(%s); \n " ) , * Delegate , * DelegateToAdd ) ) ;
2014-03-14 14:13:41 -04:00
}
2015-03-30 14:10:13 -04:00
void FBlueprintCompilerCppBackend : : EmitRemoveMulticastDelegateStatement ( FKismetFunctionContext & FunctionContext , FBlueprintCompiledStatement & Statement )
2014-03-14 14:13:41 -04:00
{
2014-09-30 05:04:55 -04:00
check ( Statement . LHS & & Statement . LHS - > AssociatedVarProperty ) ;
FSafeContextScopedEmmitter SafeContextScope ( Body , Statement . LHS - > Context , * this , TEXT ( " \t \t \t " ) ) ;
Emit ( Body , TEXT ( " \t \t \t " ) ) ;
Emit ( Body , * SafeContextScope . GetAdditionalIndent ( ) ) ;
2014-03-14 14:13:41 -04:00
const FString Delegate = TermToText ( Statement . LHS ) ;
const FString DelegateToAdd = TermToText ( Statement . RHS [ 0 ] ) ;
2014-09-30 05:04:55 -04:00
Emit ( Body , * FString : : Printf ( TEXT ( " %s.Remove(%s); \n " ) , * Delegate , * DelegateToAdd ) ) ;
2014-03-14 14:13:41 -04:00
}
2015-03-30 14:10:13 -04:00
void FBlueprintCompilerCppBackend : : EmitBindDelegateStatement ( FKismetFunctionContext & FunctionContext , FBlueprintCompiledStatement & Statement )
2014-03-14 14:13:41 -04:00
{
check ( 2 = = Statement . RHS . Num ( ) ) ;
2014-09-30 05:04:55 -04:00
check ( Statement . LHS ) ;
FSafeContextScopedEmmitter SafeContextScope ( Body , Statement . LHS - > Context , * this , TEXT ( " \t \t \t " ) ) ;
Emit ( Body , TEXT ( " \t \t \t " ) ) ;
Emit ( Body , * SafeContextScope . GetAdditionalIndent ( ) ) ;
2014-03-14 14:13:41 -04:00
const FString Delegate = TermToText ( Statement . LHS ) ;
2014-09-23 13:19:42 -04:00
const FString NameTerm = TermToText ( Statement . RHS [ 0 ] , GetDefault < UNameProperty > ( ) ) ;
const FString ObjectTerm = TermToText ( Statement . RHS [ 1 ] , GetDefault < UObjectProperty > ( ) ) ;
2014-03-14 14:13:41 -04:00
2014-09-30 05:04:55 -04:00
Emit ( Body , * FString : : Printf ( TEXT ( " %s.BindUFunction(%s,%s); \n " ) , * Delegate , * ObjectTerm , * NameTerm ) ) ;
2014-03-14 14:13:41 -04:00
}
2015-03-30 14:10:13 -04:00
void FBlueprintCompilerCppBackend : : EmitClearMulticastDelegateStatement ( FKismetFunctionContext & FunctionContext , FBlueprintCompiledStatement & Statement )
2014-03-14 14:13:41 -04:00
{
2014-09-30 05:04:55 -04:00
check ( Statement . LHS ) ;
FSafeContextScopedEmmitter SafeContextScope ( Body , Statement . LHS - > Context , * this , TEXT ( " \t \t \t " ) ) ;
Emit ( Body , TEXT ( " \t \t \t " ) ) ;
Emit ( Body , * SafeContextScope . GetAdditionalIndent ( ) ) ;
2014-03-14 14:13:41 -04:00
const FString Delegate = TermToText ( Statement . LHS ) ;
2014-09-30 05:04:55 -04:00
Emit ( Body , * FString : : Printf ( TEXT ( " %s.Clear(); \n " ) , * Delegate ) ) ;
2014-03-14 14:13:41 -04:00
}
2015-03-30 14:10:13 -04:00
void FBlueprintCompilerCppBackend : : EmitCreateArrayStatement ( FKismetFunctionContext & FunctionContext , FBlueprintCompiledStatement & Statement )
2014-03-14 14:13:41 -04:00
{
FBPTerminal * ArrayTerm = Statement . LHS ;
const FString Array = TermToText ( ArrayTerm ) ;
UArrayProperty * ArrayProperty = CastChecked < UArrayProperty > ( ArrayTerm - > AssociatedVarProperty ) ;
UProperty * InnerProperty = ArrayProperty - > Inner ;
2015-03-30 14:10:13 -04:00
for ( int32 i = 0 ; i < Statement . RHS . Num ( ) ; + + i )
2014-03-14 14:13:41 -04:00
{
FBPTerminal * CurrentTerminal = Statement . RHS [ i ] ;
2015-03-30 14:10:13 -04:00
Emit ( Body ,
2014-03-14 14:13:41 -04:00
* FString : : Printf (
2015-03-30 14:10:13 -04:00
TEXT ( " \t \t \t %s[%d] = %s; " ) ,
* Array ,
i ,
* TermToText ( CurrentTerminal , ( CurrentTerminal - > bIsLiteral ? InnerProperty : NULL ) ) ) ) ;
2014-03-14 14:13:41 -04:00
}
}
2015-03-30 14:10:13 -04:00
void FBlueprintCompilerCppBackend : : EmitGotoStatement ( FKismetFunctionContext & FunctionContext , FBlueprintCompiledStatement & Statement )
2014-03-14 14:13:41 -04:00
{
if ( Statement . Type = = KCST_ComputedGoto )
{
FString NextStateExpression ;
NextStateExpression = TermToText ( Statement . LHS , ( UProperty * ) ( GetDefault < UIntProperty > ( ) ) ) ;
Emit ( Body , * FString : : Printf ( TEXT ( " \t \t \t CurrentState = %s; \n " ) , * NextStateExpression ) ) ;
Emit ( Body , * FString : : Printf ( TEXT ( " \t \t \t break; \n " ) ) ) ;
}
2014-12-10 10:27:33 -05:00
else if ( ( Statement . Type = = KCST_GotoIfNot ) | | ( Statement . Type = = KCST_EndOfThreadIfNot ) | | ( Statement . Type = = KCST_GotoReturnIfNot ) )
2014-03-14 14:13:41 -04:00
{
FString ConditionExpression ;
ConditionExpression = TermToText ( Statement . LHS , ( UProperty * ) ( GetDefault < UBoolProperty > ( ) ) ) ;
Emit ( Body , * FString : : Printf ( TEXT ( " \t \t \t if (!%s) \n " ) , * ConditionExpression ) ) ;
Emit ( Body , * FString : : Printf ( TEXT ( " \t \t \t { \n " ) ) ) ;
if ( Statement . Type = = KCST_EndOfThreadIfNot )
{
2014-12-10 10:27:33 -05:00
ensure ( FunctionContext . bUseFlowStack ) ;
2015-03-27 20:05:10 -04:00
Emit ( Body , TEXT ( " \t \t \t \t CurrentState = (StateStack.Num() > 0) ? StateStack.Pop(/*bAllowShrinking=*/ false) : -1; \n " ) ) ;
2014-03-14 14:13:41 -04:00
}
2014-12-10 10:27:33 -05:00
else if ( Statement . Type = = KCST_GotoReturnIfNot )
{
Emit ( Body , TEXT ( " \t \t \t \t CurrentState = -1; \n " ) ) ;
}
2014-03-14 14:13:41 -04:00
else
{
Emit ( Body , * FString : : Printf ( TEXT ( " \t \t \t \t CurrentState = %d; \n " ) , StatementToStateIndex ( FunctionContext , Statement . TargetLabel ) ) ) ;
}
Emit ( Body , * FString : : Printf ( TEXT ( " \t \t \t \t break; \n " ) ) ) ;
Emit ( Body , * FString : : Printf ( TEXT ( " \t \t \t } \n " ) ) ) ;
}
2014-12-10 10:27:33 -05:00
else if ( Statement . Type = = KCST_GotoReturn )
{
Emit ( Body , TEXT ( " \t \t \t CurrentState = -1; \n " ) ) ;
}
2014-03-14 14:13:41 -04:00
else
{
Emit ( Body , * FString : : Printf ( TEXT ( " \t \t \t CurrentState = %d; \n " ) , StatementToStateIndex ( FunctionContext , Statement . TargetLabel ) ) ) ;
Emit ( Body , * FString : : Printf ( TEXT ( " \t \t \t break; \n " ) ) ) ;
}
}
2015-03-30 14:10:13 -04:00
void FBlueprintCompilerCppBackend : : EmitPushStateStatement ( FKismetFunctionContext & FunctionContext , FBlueprintCompiledStatement & Statement )
2014-03-14 14:13:41 -04:00
{
2014-12-10 10:27:33 -05:00
ensure ( FunctionContext . bUseFlowStack ) ;
2014-03-14 14:13:41 -04:00
Emit ( Body , * FString : : Printf ( TEXT ( " \t \t \t StateStack.Push(%d); \n " ) , StatementToStateIndex ( FunctionContext , Statement . TargetLabel ) ) ) ;
}
2015-03-30 14:10:13 -04:00
void FBlueprintCompilerCppBackend : : EmitEndOfThreadStatement ( FKismetFunctionContext & FunctionContext , const FString & ReturnValueString )
2014-03-14 14:13:41 -04:00
{
2014-12-10 10:27:33 -05:00
ensure ( FunctionContext . bUseFlowStack ) ;
2015-03-27 20:05:10 -04:00
Emit ( Body , TEXT ( " \t \t \t CurrentState = (StateStack.Num() > 0) ? StateStack.Pop(/*bAllowShrinking=*/ false) : -1; \n " ) ) ;
2014-03-14 14:13:41 -04:00
Emit ( Body , TEXT ( " \t \t \t break; \n " ) ) ;
}
2015-03-30 14:10:13 -04:00
void FBlueprintCompilerCppBackend : : EmitReturnStatement ( FKismetFunctionContext & FunctionContext , const FString & ReturnValueString )
2014-03-14 14:13:41 -04:00
{
Emit ( Body , * FString : : Printf ( TEXT ( " \t return%s; \n " ) , * ReturnValueString ) ) ;
}
2015-03-30 14:10:13 -04:00
void FBlueprintCompilerCppBackend : : DeclareLocalVariables ( FKismetFunctionContext & FunctionContext , TArray < UProperty * > & LocalVariables )
2014-03-14 14:13:41 -04:00
{
for ( int32 i = 0 ; i < LocalVariables . Num ( ) ; + + i )
{
UProperty * LocalVariable = LocalVariables [ i ] ;
Emit ( Body , TEXT ( " \t " ) ) ;
2014-09-30 05:04:55 -04:00
LocalVariable - > ExportCppDeclaration ( Body , EExportedDeclaration : : Local , NULL , EPropertyExportCPPFlags : : CPPF_CustomTypeName ) ;
2015-03-30 14:10:13 -04:00
Emit ( Body , TEXT ( " {}; \n " ) ) ;
2014-03-14 14:13:41 -04:00
}
if ( LocalVariables . Num ( ) > 0 )
{
Emit ( Body , TEXT ( " \n " ) ) ;
}
}
2015-03-30 14:10:13 -04:00
void FBlueprintCompilerCppBackend : : DeclareStateSwitch ( FKismetFunctionContext & FunctionContext )
2014-03-14 14:13:41 -04:00
{
2014-12-10 10:27:33 -05:00
if ( FunctionContext . bUseFlowStack )
{
Emit ( Body , TEXT ( " \t TArray< int32, TInlineAllocator<8> > StateStack; \n " ) ) ;
}
2014-03-14 14:13:41 -04:00
Emit ( Body , TEXT ( " \t int32 CurrentState = 0; \n " ) ) ;
Emit ( Body , TEXT ( " \t do \n " ) ) ;
Emit ( Body , TEXT ( " \t { \n " ) ) ;
Emit ( Body , TEXT ( " \t \t switch( CurrentState ) \n " ) ) ;
Emit ( Body , TEXT ( " \t \t { \n " ) ) ;
Emit ( Body , TEXT ( " \t \t case 0: \n " ) ) ;
}
2015-03-30 14:10:13 -04:00
void FBlueprintCompilerCppBackend : : CloseStateSwitch ( FKismetFunctionContext & FunctionContext )
2014-03-14 14:13:41 -04:00
{
// Default error-catching case
Emit ( Body , TEXT ( " \t \t default: \n " ) ) ;
2014-12-10 10:27:33 -05:00
if ( FunctionContext . bUseFlowStack )
{
Emit ( Body , TEXT ( " \t \t \t check(false); // Invalid state \n " ) ) ;
}
2014-03-14 14:13:41 -04:00
Emit ( Body , TEXT ( " \t \t \t break; \n " ) ) ;
// Close the switch block and do-while loop
Emit ( Body , TEXT ( " \t \t } \n " ) ) ;
Emit ( Body , TEXT ( " \t } while( CurrentState != -1 ); \n " ) ) ;
}
2015-03-30 14:10:13 -04:00
void FBlueprintCompilerCppBackend : : ConstructFunction ( FKismetFunctionContext & FunctionContext , bool bGenerateStubOnly )
2014-03-14 14:13:41 -04:00
{
2014-09-30 05:04:55 -04:00
if ( FunctionContext . IsDelegateSignature ( ) )
{
return ;
}
2014-03-14 14:13:41 -04:00
UFunction * Function = FunctionContext . Function ;
UProperty * ReturnValue = NULL ;
TArray < UProperty * > LocalVariables ;
2015-03-30 14:10:13 -04:00
2014-03-14 14:13:41 -04:00
{
2014-09-30 05:04:55 -04:00
FString FunctionName ;
Function - > GetName ( FunctionName ) ;
TArray < UProperty * > ArgumentList ;
// Split the function property list into arguments, a return value (if any), and local variable declarations
for ( TFieldIterator < UProperty > It ( Function ) ; It ; + + It )
2014-03-14 14:13:41 -04:00
{
2014-09-30 05:04:55 -04:00
UProperty * Property = * It ;
if ( Property - > HasAnyPropertyFlags ( CPF_Parm ) )
2014-03-14 14:13:41 -04:00
{
2014-09-30 05:04:55 -04:00
if ( Property - > HasAnyPropertyFlags ( CPF_ReturnParm ) )
2014-03-14 14:13:41 -04:00
{
2014-09-30 05:04:55 -04:00
if ( ReturnValue = = NULL )
{
ReturnValue = Property ;
LocalVariables . Add ( Property ) ;
}
else
{
MessageLog . Error ( * FString : : Printf ( TEXT ( " Function %s from graph @@ has more than one return value (named %s and %s) " ) ,
* FunctionName , * ReturnValue - > GetName ( ) , * Property - > GetName ( ) ) , FunctionContext . SourceGraph ) ;
}
2014-03-14 14:13:41 -04:00
}
else
{
2014-09-30 05:04:55 -04:00
ArgumentList . Add ( Property ) ;
2014-03-14 14:13:41 -04:00
}
}
else
{
2014-09-30 05:04:55 -04:00
LocalVariables . Add ( Property ) ;
}
2014-03-14 14:13:41 -04:00
}
2014-09-30 05:04:55 -04:00
// Emit the declaration
const FString ReturnType = ReturnValue ? ReturnValue - > GetCPPType ( NULL , EPropertyExportCPPFlags : : CPPF_CustomTypeName ) : TEXT ( " void " ) ;
//@TODO: Make the header+body export more uniform
2014-03-14 14:13:41 -04:00
{
2014-09-30 05:04:55 -04:00
const FString Start = FString : : Printf ( TEXT ( " %s %s%s%s( " ) , * ReturnType , TEXT ( " %s " ) , TEXT ( " %s " ) , * FunctionName ) ;
2014-03-14 14:13:41 -04:00
2015-03-23 14:35:43 -04:00
Emit ( Header , * FString : : Printf ( TEXT ( " \t %s \n " ) , * FEmitHelper : : EmitUFuntion ( Function ) ) ) ;
2014-09-30 05:04:55 -04:00
Emit ( Header , TEXT ( " \t " ) ) ;
2015-03-30 14:10:13 -04:00
if ( Function - > HasAllFunctionFlags ( FUNC_Static ) )
{
Emit ( Header , TEXT ( " static " ) ) ;
}
2014-09-30 05:04:55 -04:00
Emit ( Header , * FString : : Printf ( * Start , TEXT ( " " ) , TEXT ( " " ) ) ) ;
Emit ( Body , * FString : : Printf ( * Start , * CppClassName , TEXT ( " :: " ) ) ) ;
for ( int32 i = 0 ; i < ArgumentList . Num ( ) ; + + i )
{
UProperty * ArgProperty = ArgumentList [ i ] ;
if ( i > 0 )
{
Emit ( Header , TEXT ( " , " ) ) ;
Emit ( Body , TEXT ( " , " ) ) ;
}
if ( ArgProperty - > HasAnyPropertyFlags ( CPF_OutParm ) )
{
Emit ( Header , TEXT ( " /*out*/ " ) ) ;
Emit ( Body , TEXT ( " /*out*/ " ) ) ;
}
ArgProperty - > ExportCppDeclaration ( Header , EExportedDeclaration : : Parameter , NULL , EPropertyExportCPPFlags : : CPPF_CustomTypeName ) ;
ArgProperty - > ExportCppDeclaration ( Body , EExportedDeclaration : : Parameter , NULL , EPropertyExportCPPFlags : : CPPF_CustomTypeName ) ;
2014-03-14 14:13:41 -04:00
}
2014-09-30 05:04:55 -04:00
Emit ( Header , TEXT ( " ) " ) ) ;
Emit ( Header , TEXT ( " ; \n " ) ) ;
Emit ( Body , TEXT ( " ) \n " ) ) ;
2014-03-14 14:13:41 -04:00
}
2014-09-30 05:04:55 -04:00
// Start the body of the implementation
Emit ( Body , TEXT ( " { \n " ) ) ;
2014-03-14 14:13:41 -04:00
}
2014-09-30 05:04:55 -04:00
const FString ReturnValueString = ReturnValue ? ( FString ( TEXT ( " " ) ) + ReturnValue - > GetName ( ) ) : TEXT ( " " ) ;
2014-03-14 14:13:41 -04:00
2015-03-30 14:10:13 -04:00
if ( ! bGenerateStubOnly )
2014-03-14 14:13:41 -04:00
{
// Emit local variables
DeclareLocalVariables ( FunctionContext , LocalVariables ) ;
2014-12-10 10:27:33 -05:00
bool bUseSwitchState = false ;
for ( auto Node : FunctionContext . LinearExecutionList )
{
TArray < FBlueprintCompiledStatement * > * StatementList = FunctionContext . StatementsPerNode . Find ( Node ) ;
if ( StatementList )
{
for ( auto Statement : ( * StatementList ) )
{
if ( Statement & & (
Statement - > Type = = KCST_UnconditionalGoto | |
Statement - > Type = = KCST_PushState | |
Statement - > Type = = KCST_GotoIfNot | |
Statement - > Type = = KCST_ComputedGoto | |
Statement - > Type = = KCST_EndOfThread | |
Statement - > Type = = KCST_EndOfThreadIfNot | |
Statement - > Type = = KCST_GotoReturn | |
Statement - > Type = = KCST_GotoReturnIfNot ) )
{
bUseSwitchState = true ;
break ;
}
}
}
if ( bUseSwitchState )
{
break ;
}
}
if ( bUseSwitchState )
{
DeclareStateSwitch ( FunctionContext ) ;
}
2014-03-14 14:13:41 -04:00
// Run thru code looking only at things marked as jump targets, to make sure the jump targets are ordered in order of appearance in the linear execution list
// Emit code in the order specified by the linear execution list (the first node is always the entry point for the function)
for ( int32 NodeIndex = 0 ; NodeIndex < FunctionContext . LinearExecutionList . Num ( ) ; + + NodeIndex )
{
UEdGraphNode * StatementNode = FunctionContext . LinearExecutionList [ NodeIndex ] ;
TArray < FBlueprintCompiledStatement * > * StatementList = FunctionContext . StatementsPerNode . Find ( StatementNode ) ;
if ( StatementList ! = NULL )
{
for ( int32 StatementIndex = 0 ; StatementIndex < StatementList - > Num ( ) ; + + StatementIndex )
{
FBlueprintCompiledStatement & Statement = * ( ( * StatementList ) [ StatementIndex ] ) ;
if ( Statement . bIsJumpTarget )
{
// Just making sure we number them in order of appearance, so jump statements don't influence the order
const int32 StateNum = StatementToStateIndex ( FunctionContext , & Statement ) ;
}
}
}
}
// Emit code in the order specified by the linear execution list (the first node is always the entry point for the function)
for ( int32 NodeIndex = 0 ; NodeIndex < FunctionContext . LinearExecutionList . Num ( ) ; + + NodeIndex )
{
UEdGraphNode * StatementNode = FunctionContext . LinearExecutionList [ NodeIndex ] ;
TArray < FBlueprintCompiledStatement * > * StatementList = FunctionContext . StatementsPerNode . Find ( StatementNode ) ;
if ( StatementList ! = NULL )
{
for ( int32 StatementIndex = 0 ; StatementIndex < StatementList - > Num ( ) ; + + StatementIndex )
{
FBlueprintCompiledStatement & Statement = * ( ( * StatementList ) [ StatementIndex ] ) ;
2014-12-10 10:27:33 -05:00
if ( Statement . bIsJumpTarget & & bUseSwitchState )
2014-03-14 14:13:41 -04:00
{
const int32 StateNum = StatementToStateIndex ( FunctionContext , & Statement ) ;
Emit ( Body , * FString : : Printf ( TEXT ( " \n \t \t case %d: \n " ) , StateNum ) ) ;
}
switch ( Statement . Type )
{
case KCST_Nop :
Emit ( Body , TEXT ( " \t \t \t //No operation. \n " ) ) ;
break ;
case KCST_WireTraceSite :
Emit ( Body , TEXT ( " \t \t \t // Wire debug site. \n " ) ) ;
break ;
case KCST_DebugSite :
Emit ( Body , TEXT ( " \t \t \t // Debug site. \n " ) ) ;
break ;
case KCST_CallFunction :
EmitCallStatment ( FunctionContext , Statement ) ;
break ;
case KCST_CallDelegate :
EmitCallDelegateStatment ( FunctionContext , Statement ) ;
break ;
case KCST_Assignment :
EmitAssignmentStatment ( FunctionContext , Statement ) ;
break ;
2014-04-02 18:09:23 -04:00
case KCST_CastObjToInterface :
EmitCastObjToInterfaceStatement ( FunctionContext , Statement ) ;
break ;
case KCST_CrossInterfaceCast :
EmitCastBetweenInterfacesStatement ( FunctionContext , Statement ) ;
2014-03-14 14:13:41 -04:00
break ;
2014-10-23 12:15:59 -04:00
case KCST_CastInterfaceToObj :
EmitCastInterfaceToObjStatement ( FunctionContext , Statement ) ;
break ;
2014-03-14 14:13:41 -04:00
case KCST_DynamicCast :
EmitDynamicCastStatement ( FunctionContext , Statement ) ;
break ;
case KCST_ObjectToBool :
EmitObjectToBoolStatement ( FunctionContext , Statement ) ;
break ;
case KCST_AddMulticastDelegate :
EmitAddMulticastDelegateStatement ( FunctionContext , Statement ) ;
break ;
case KCST_RemoveMulticastDelegate :
EmitRemoveMulticastDelegateStatement ( FunctionContext , Statement ) ;
break ;
case KCST_BindDelegate :
EmitBindDelegateStatement ( FunctionContext , Statement ) ;
break ;
case KCST_ClearMulticastDelegate :
EmitClearMulticastDelegateStatement ( FunctionContext , Statement ) ;
break ;
case KCST_CreateArray :
EmitCreateArrayStatement ( FunctionContext , Statement ) ;
break ;
case KCST_ComputedGoto :
case KCST_UnconditionalGoto :
case KCST_GotoIfNot :
case KCST_EndOfThreadIfNot :
2014-12-10 10:27:33 -05:00
case KCST_GotoReturn :
case KCST_GotoReturnIfNot :
2014-03-14 14:13:41 -04:00
EmitGotoStatement ( FunctionContext , Statement ) ;
break ;
case KCST_PushState :
EmitPushStateStatement ( FunctionContext , Statement ) ;
break ;
case KCST_EndOfThread :
EmitEndOfThreadStatement ( FunctionContext , ReturnValueString ) ;
break ;
case KCST_Comment :
Emit ( Body , * FString : : Printf ( TEXT ( " \t \t \t // %s \n " ) , * Statement . Comment ) ) ;
break ;
2014-09-15 06:09:48 -04:00
case KCST_MetaCast :
EmitMetaCastStatement ( FunctionContext , Statement ) ;
break ;
case KCST_Return :
Emit ( Body , TEXT ( " \t \t \t // Return statement. \n " ) ) ;
break ;
2014-03-14 14:13:41 -04:00
default :
Emit ( Body , TEXT ( " \t // Warning: Ignoring unsupported statement \n " ) ) ;
UE_LOG ( LogK2Compiler , Warning , TEXT ( " C++ backend encountered unsupported statement type %d " ) , ( int32 ) Statement . Type ) ;
break ;
} ;
}
}
}
2014-12-10 10:27:33 -05:00
if ( bUseSwitchState )
{
CloseStateSwitch ( FunctionContext ) ;
}
2014-03-14 14:13:41 -04:00
}
EmitReturnStatement ( FunctionContext , ReturnValueString ) ;
2015-03-30 14:10:13 -04:00
2014-03-14 14:13:41 -04:00
Emit ( Body , TEXT ( " } \n \n " ) ) ;
2015-03-30 14:10:13 -04:00
}