Files
UnrealEngine/Engine/Source/Runtime/VerseCompiler/Public/uLang/Semantics/Expression.h
2025-05-18 13:04:45 +08:00

3595 lines
146 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
// uLang Compiler Public API
#pragma once
#include "uLang/Common/Containers/SharedPointer.h"
#include "uLang/Common/Containers/SharedPointerArray.h"
#include "uLang/Common/Templates/Conditionals.h"
#include "uLang/Common/Text/Symbol.h"
#include "uLang/Common/Text/UTF8String.h"
#include "uLang/Semantics/DataDefinition.h"
#include "uLang/Semantics/SemanticTypes.h"
#include "uLang/Semantics/Signature.h"
#include "uLang/SourceProject/PackageRole.h"
#include "uLang/Syntax/VstNode.h"
#define UE_API VERSECOMPILER_API
namespace uLang
{
// Forward declarations
class CEnumeration;
class CAstNode;
class CAstCompilationUnit;
class CExpressionBase;
class CExprCodeBlock;
class CExprIdentifierBase;
class CSemanticProgram;
class CSnippet;
class CModule;
class CModulePart;
class CModuleAlias;
class CControlScope;
class CTypeAlias;
class CTypeVariable;
class CEnumerator;
// NOTE: (YiLiangSiew) Currently, Visual Verse relies on the numerical values of these enumerations. If you
// change this, be sure to update `BaseVisualVerseSettings.ini` as well.
#define VERSE_VISIT_AST_NODE_TYPES(v) \
/* Helper expressions */ \
v(Error_, CExprError) /* An expression that could not be analyzed due to an error. Attempts to analyze should propagate the error. */ \
v(Placeholder_, CExprPlaceholder) /* Corresponds to a Placeholder Vst node. */ \
v(External, CExprExternal) /* An (unknown) external expression - should never reach the code generator */ \
v(PathPlusSymbol, CExprPathPlusSymbol) /* Path of the current scope plus a symbol - /unrealengine.com/UnrealEngine@5 */ \
\
/* Literals */ \
v(Literal_Logic, CExprLogic) /* Logic literal - true/false */ \
v(Literal_Number, CExprNumber) /* Integer literal - 42, 0, -123, 123_456_789, 0x12fe, 0b101010 */ \
/* or Float literal - 42.0, 0.0, -123.0, 123_456.0, 3.14159, .5, -.33, 4.2e1, -1e6, 7.5e-8 */ \
v(Literal_Char, CExprChar) /* Character literal - 'a', '\n' */ \
v(Literal_String, CExprString) /* String literal - "Hello, world!", "Line 1\nLine2" */ \
v(Literal_Path, CExprPath) /* Path literal - /unrealengine.com/UnrealEngine@5 */ \
v(Literal_Enum, CExprEnumLiteral) /* Enumerator - Color.Red, Size.XXL */ \
v(Literal_Type, CExprType) /* Type - type{<expr>} */ \
v(Literal_Function, CExprFunctionLiteral) /* a=>b or function(a){b} */ \
\
/* Identifiers */ \
v(Identifier_Unresolved, CExprIdentifierUnresolved) /* An existing identifier that is unresolved. It is produced by desugaring and consumed by analysis. */ \
v(Identifier_Class, CExprIdentifierClass) /* Type identifier - e.g. my_type, int, color, string */ \
v(Identifier_Module, CExprIdentifierModule) /* Module name */ \
v(Identifier_ModuleAlias, CExprIdentifierModuleAlias) /* Module alias name */ \
v(Identifier_Enum, CExprEnumerationType) /* Enum name */ \
v(Identifier_Interface, CExprInterfaceType) /* Interface name */ \
v(Identifier_Data, CExprIdentifierData) /* Scoped data-definition (class member, local, etc.) */ \
v(Identifier_TypeAlias, CExprIdentifierTypeAlias) /* Access to type alias */ \
v(Identifier_TypeVariable, CExprIdentifierTypeVariable) /* Access to a type variable */ \
v(Identifier_Function, CExprIdentifierFunction) /* Access to functions */ \
v(Identifier_OverloadedFunction, CExprIdentifierOverloadedFunction) /* An overloaded function identifier that hasn't been resolved to a specific overload. */ \
v(Identifier_Self, CExprSelf) /* Access to the instance the current function is being invoked on. */ \
v(Identifier_Local, CExprLocal) /* Access to the the current scope for the identifier that has this qualifier. */ \
v(Identifier_BuiltInMacro, CExprIdentifierBuiltInMacro) /* An intrinsic macro: option{}, logic{}, array{}, etc. */ \
\
/* Multi purpose syntax */ \
v(Definition, CExprDefinition) /* represents syntactic forms elt:domain=value, elt:domain, elt=value */ \
\
/* Macro */ \
v(MacroCall, CExprMacroCall) /* macro invocations should be resolved by the compiler; the code generator should never encounter this. */ \
\
/* Invocations */ \
v(Invoke_Invocation, CExprInvocation) /* Routine call - expr1.call(expr2, expr3) */ \
v(Invoke_UnaryArithmetic, CExprUnaryArithmetic) /* negation */ \
v(Invoke_BinaryArithmetic, CExprBinaryArithmetic) /* add, sub, mul, div; two operands only */ \
v(Invoke_ShortCircuitAnd, CExprShortCircuitAnd) /* short-circuit evaluation of logic and */ \
v(Invoke_ShortCircuitOr, CExprShortCircuitOr) /* short-circuit evaluation of logic or */ \
v(Invoke_LogicalNot, CExprLogicalNot) /* logical not operator */ \
v(Invoke_Comparison, CExprComparison) /* comparison operators */ \
v(Invoke_QueryValue, CExprQueryValue) /* Querying the value of a logic or option. */ \
v(Invoke_MakeOption, CExprMakeOption) /* Making an option value. */ \
v(Invoke_MakeArray, CExprMakeArray) /* Making an array value. */ \
v(Invoke_MakeMap, CExprMakeMap) /* Making a map value. */ \
v(Invoke_MakeTuple, CExprMakeTuple) /* Making a tuple value - (1, 2.0f, "three") */ \
v(Invoke_TupleElement, CExprTupleElement) /* Tuple element access `TupleExpr(Idx)` */ \
v(Invoke_MakeRange, CExprMakeRange) /* Making a range value. */ \
v(Invoke_Type, CExprInvokeType) /* Invoke a type as a function on a value - type(expr) or type[expr]. */ \
v(Invoke_PointerToReference, CExprPointerToReference) /* Access the mutable reference behind the pointer. */ \
v(Invoke_Set, CExprSet) /* Evaluate operand to an l-expression. */ \
v(Invoke_NewPointer, CExprNewPointer) /* Create a new pointer from an initial value. */ \
v(Invoke_ReferenceToValue, CExprReferenceToValue) /* Evaluates the value of an expression yielding a reference type. */ \
\
v(Assignment, CExprAssignment) /* Assignment operation - expr1 = expr2, expr1 := expr2, expr1 += expr2, etc. */ \
\
/* TypeFormers */ \
v(Invoke_ArrayFormer, CExprArrayTypeFormer) /* Invoke (at compile time) a formation of an array of another type */ \
v(Invoke_GeneratorFormer, CExprGeneratorTypeFormer) /* Invoke (at compile time) a formation of an generator type. */ \
v(Invoke_MapFormer, CExprMapTypeFormer) /* Invoke (at compile time) a formation of a map from a key and value type. */ \
v(Invoke_OptionFormer, CExprOptionTypeFormer) /* Invoke (at compile time) a formation of an option of some primitive type */ \
v(Invoke_Subtype, CExprSubtype) /* Invoke (at compile time) a formation of a metaclass type. */ \
v(Invoke_TupleType, CExprTupleType) /* Get or create a tuple based on `tuple(type1, type2, ...)` */ \
v(Invoke_Arrow, CExprArrow) /* Create a function type from a parameter and return type. */ \
\
v(Invoke_ArchetypeInstantiation, CExprArchetypeInstantiation) /* Initializer list style instantiation - Type{expr1, id=expr2, ...} */ \
\
/* Flow Control */ \
v(Flow_CodeBlock, CExprCodeBlock) /* Code block - block {expr1; expr2} */ \
v(Flow_Let, CExprLet) /* let {definition1; definition2} */ \
v(Flow_Defer, CExprDefer) /* defer {expr1; expr2} */ \
v(Flow_If, CExprIf) /* Conditional with failable tests- if (Test[]) {clause1}, if (Test[]) {clause1} else {else_clause} */ \
v(Flow_Iteration, CExprIteration) /* Bounded iteration over an iterable type - for(Num:Nums, ...) {DoStuff(Num, ...)} */ \
v(Flow_Loop, CExprLoop) /* Simple loop - loop {DoStuff()} */ \
v(Flow_Break, CExprBreak) /* Control flow early exit - loop {if (IsEarlyExit[]) {break}; DoLoopStuff()} */ \
v(Flow_Return, CExprReturn) /* Return statement - return expr */ \
v(Flow_ProfileBlock, CExprProfileBlock) /* profile block */\
\
v(Ir_For, CIrFor) /* Bounded iteration over an iterable type - for(Num:Nums) {DoStuff(Num)} */ \
v(Ir_ForBody, CIrForBody) /* Only used inside CIrFor, and only around the body of the innermost CIrFor */ \
v(Ir_ArrayAdd, CIrArrayAdd) /* Append an item to an array */ \
v(Ir_MapAdd, CIrMapAdd) /* Add a key-value pair to a map */ \
v(Ir_ArrayUnsafeCall, CIrArrayUnsafeCall) /* Infallibly access an element of an array */ \
v(Ir_ConvertToDynamic, CIrConvertToDynamic) /* Converts a value to a dynamically typed value. */ \
v(Ir_ConvertFromDynamic, CIrConvertFromDynamic) /* Converts a value from a dynamically typed value. */ \
\
/* Concurrency Primitives */ \
v(Concurrent_Sync, CExprSync) /* sync {Coro1(); Coro2()} */ \
v(Concurrent_Rush, CExprRush) /* rush {Coro1(); Coro2()} */ \
v(Concurrent_Race, CExprRace) /* race {Coro1(); Coro2()} */ \
v(Concurrent_SyncIterated, CExprSyncIterated) /* sync(Item:Container) {Item.Coro1(); Coro2(Item)} */ \
v(Concurrent_RushIterated, CExprRushIterated) /* rush(Item:Container) {Item.Coro1(); Coro2(Item)} */ \
v(Concurrent_RaceIterated, CExprRaceIterated) /* race(Item:Container) {Item.Coro1(); Coro2(Item)} */ \
v(Concurrent_Branch, CExprBranch) /* branch {Coro1(); Coro2()} */ \
v(Concurrent_Spawn, CExprSpawn) /* spawn {Coro()} */ \
\
/* Definitions */ \
v(Definition_Module, CExprModuleDefinition) \
v(Definition_Enum, CExprEnumDefinition) \
v(Definition_Interface, CExprInterfaceDefinition) \
v(Definition_Class, CExprClassDefinition) \
v(Definition_Data, CExprDataDefinition) \
v(Definition_IterationPair, CExprIterationPairDefinition) \
v(Definition_Function, CExprFunctionDefinition) \
v(Definition_TypeAlias, CExprTypeAliasDefinition) \
v(Definition_Using, CExprUsing) \
v(Definition_Import, CExprImport) \
v(Definition_Where, CExprWhere) \
v(Definition_Var, CExprVar) \
v(Definition_ScopedAccessLevel, CExprScopedAccessLevelDefinition) \
v(Invoke_MakeNamed, CExprMakeNamed) /* ?ParamName:=Value pair - or default value placeholder (value not set) */ \
\
/* Containing Context - may contain expressions though they aren't expressions themselves */ \
v(Context_Project, CAstProject) \
v(Context_CompilationUnit, CAstCompilationUnit) \
v(Context_Package, CAstPackage) \
v(Context_Snippet, CExprSnippet)
#define FORWARD_DECLARE(_, Class) class Class;
VERSE_VISIT_AST_NODE_TYPES(FORWARD_DECLARE)
#undef FORWARD_DECLARE
/**
* This is used to differentiate between different types of AST nodes when it is only
* known that an instance is of type CAstNode, but not the specific subclass.
* It is returned by the method CAstNode::GetNodeType()
**/
enum class EAstNodeType : uint8_t
{
#define VISIT_AST_NODE_TYPE(Name, Class) Name,
VERSE_VISIT_AST_NODE_TYPES(VISIT_AST_NODE_TYPE)
#undef VISIT_AST_NODE_TYPE
};
struct SAstNodeTypeInfo
{
const char* _EnumeratorName;
const char* _CppClassName;
};
/** Returns the name of an AST node type. */
VERSECOMPILER_API SAstNodeTypeInfo GetAstNodeTypeInfo(uLang::EAstNodeType Type);
//---------------------------------------------------------------------------------------
// Indicates whether an expression should return immediately - such as functions, after a
// duration (including immediately) such as coroutines or either.
enum class EInvokeTime : uint8_t
{
Immediate = 1 << 0, // May only call an immediate expression (such as a function call) and any async expression (such as a coroutine call) should result in an error.
Async = 1 << 1, // May only call an async expression (such as a coroutine call) and any immediate expression (such as a function call) should result in an error. Only true within one of the pre-defined calling contexts (`sync{}`, `race{}`, etc.).
Any_ = Immediate | Async // Calling either immediate or async expressions is allowed.
};
inline const char* InvokeTimeAsCString(EInvokeTime InvokeTime)
{
switch(InvokeTime)
{
case EInvokeTime::Immediate: return "Immediate";
case EInvokeTime::Async: return "Async";
case EInvokeTime::Any_: return "Any_";
default: ULANG_UNREACHABLE();
}
}
/**
* Abstract base for applying some operation / iterating through AST structures.
* @see CAstNode::VisitChildren()
**/
struct SAstVisitor
{
/** Called when visiting an AST node **/
virtual void VisitImmediate(const char* FieldName, CUTF8StringView Value) {}
virtual void VisitImmediate(const char* FieldName, int64_t Value) {}
virtual void VisitImmediate(const char* FieldName, double Value) {}
virtual void VisitImmediate(const char* FieldName, bool Value) {}
virtual void VisitImmediate(const char* FieldName, const CTypeBase* Type) {}
virtual void VisitImmediate(const char* FieldName, const CDefinition& Definition) {}
virtual void VisitImmediate(const char* FieldName, const Verse::Vst::Node& VstNode) {}
void VisitImmediate(const char* FieldName, const char* CString) { VisitImmediate(FieldName, CUTF8StringView(CString)); }
virtual void Visit(const char* FieldName, CAstNode& AstNode) = 0;
virtual void BeginArray(const char* FieldName, intptr_t Num) {}
virtual void VisitElement(CAstNode& AstNode) = 0;
virtual void EndArray() {}
template<typename NodeType, bool bAllowNull, typename AllocatorType, typename... AllocatorArgTypes>
void Visit(const char* FieldName, const TSPtrG<NodeType, bAllowNull, AllocatorType, AllocatorArgTypes...>& NodePointer)
{
if (!bAllowNull || NodePointer.IsValid())
{
Visit(FieldName, *NodePointer);
}
}
template<typename NodeType, bool bAllowNull, typename AllocatorType, typename... AllocatorArgTypes>
void VisitElement(const TSPtrG<NodeType, bAllowNull, AllocatorType, AllocatorArgTypes...>& NodePointer)
{
if (!bAllowNull || NodePointer.IsValid())
{
VisitElement(*NodePointer);
}
}
template<typename NodeType, bool bAllowNull, typename NodeAllocatorType, typename ElementAllocatorType, typename... ElementAllocatorArgTypes>
void VisitArray(const char* FieldName, const TArrayG<TSPtrG<NodeType, bAllowNull, NodeAllocatorType>, ElementAllocatorType, ElementAllocatorArgTypes...>& Array)
{
BeginArray(FieldName, Array.Num());
for (const TSPtrG<NodeType, bAllowNull, NodeAllocatorType>& Element : Array)
{
if (!bAllowNull || Element.IsValid())
{
VisitElement(*Element);
}
}
EndArray();
}
template<typename NodeType, bool bAllowNull, typename ElementAllocatorType, typename... RawAllocatorArgTypes>
void VisitArray(const char* FieldName, const TSPtrArrayG<NodeType, bAllowNull, ElementAllocatorType, RawAllocatorArgTypes...>& Array)
{
BeginArray(FieldName, Array.Num());
for (NodeType* Node : Array)
{
if (!bAllowNull || Node)
{
VisitElement(*Node);
}
}
EndArray();
}
};
enum class EVstMappingType
{
Ast, AstNonReciprocal, Ir
};
/**
* Abstract base class for AST nodes.
*/
class CAstNode : public CSharedMix
{
public:
CAstNode(EVstMappingType VstMappingType = EVstMappingType::Ast) : _VstMappingType(VstMappingType) {}
UE_API virtual ~CAstNode();
virtual EAstNodeType GetNodeType() const = 0;
virtual const CExpressionBase* AsExpression() const { return nullptr; }
virtual CExpressionBase* AsExpression() { return nullptr; }
virtual bool MayHaveAttributes() const { return true; }
virtual const CExprIdentifierBase* AsIdentifierBase() const { return nullptr; }
/**
* Iterates over this AST node's immediate fields, calling Visitor.VisitImmediate for each immediate field.
*/
virtual void VisitImmediates(SAstVisitor& Visitor) const
{
const char* VstMappingTypeString;
switch(_VstMappingType)
{
case EVstMappingType::Ast: VstMappingTypeString = "Ast"; break;
case EVstMappingType::AstNonReciprocal: VstMappingTypeString = "AstNonReciprocal"; break;
case EVstMappingType::Ir: VstMappingTypeString = "Ir"; break;
default: ULANG_UNREACHABLE();
};
Visitor.VisitImmediate("VstMappingType", VstMappingTypeString);
if (_MappedVstNode)
{
Visitor.VisitImmediate("MappedVstNode", *_MappedVstNode);
}
}
/**
* Iterates over this AST node's direct children, calling Visitor.Visit for each child.
**/
virtual void VisitChildren(SAstVisitor& Visitor) const {}
/**
* Wrapper for VisitChildren that takes a lambda that is called for each child.
* The signature for the lambda should be (const SAstVisitor& RecurseVisitor, CAstNode&)
* You can use RecurseVisitor to recursively call VisitChildren with the same lambda.
*/
template<typename FunctionType>
ULANG_FORCEINLINE void VisitChildrenLambda(FunctionType&& Function) const;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Text methods
virtual CUTF8String GetErrorDesc() const = 0;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Syntax <> Semantic Mapping
const Verse::Vst::Node* GetMappedVstNode() const { return _MappedVstNode; }
void SetNonReciprocalMappedVstNode(const Verse::Vst::Node* VstNode)
{
_VstMappingType = EVstMappingType::AstNonReciprocal;
_MappedVstNode = VstNode;
}
void SetIrMappedVstNode(const Verse::Vst::Node* VstNode)
{
_VstMappingType = EVstMappingType::Ir;
_MappedVstNode = VstNode;
}
// True if this AstNode is used to represent an IrNode. Needed to disable some asserts and clean up code.
// Will be removed when IrNodes have their own type.
bool IsIrNode() const
{
return _VstMappingType == EVstMappingType::Ir;
}
bool IsVstMappingReciprocal() const
{
return _VstMappingType == EVstMappingType::Ast;
}
protected:
friend struct Verse::Vst::Node;
// Syntax<>Semantic mapping
mutable EVstMappingType _VstMappingType;
mutable const Verse::Vst::Node* _MappedVstNode{nullptr};
};
/**
* Abstract base class for AST expressions.
* Created from abstract syntax tree (CExpressionBase and CSemanticProgram) generated by semantic analyzer.
**/
class CExpressionBase : public CAstNode, public CAttributable
{
public:
explicit CExpressionBase(EVstMappingType VstMappingType = EVstMappingType::Ast) : CAstNode(VstMappingType) {}
explicit CExpressionBase(const CTypeBase* InResultType)
: _Report(SAnalysisResult{InResultType})
{}
virtual const CExpressionBase* AsExpression() const override { return this; }
virtual CExpressionBase* AsExpression() override { return this; }
virtual bool MayHaveAttributes() const override { return false; }
using TMacroSymbols = TArrayG<CSymbol, TInlineElementAllocator<3>>;
// True if this expression can be path of a segment. It works at all times, i.e., also before macro expression have been processed.
// The MacroSymbols argument is used in the latter case.
virtual bool CanBePathSegment(const TMacroSymbols& MacroSymbols) const { return false; }
virtual void VisitImmediates(SAstVisitor& Visitor) const override
{
CAstNode::VisitImmediates(Visitor);
if (_Report.IsSet())
{
Visitor.VisitImmediate("ResultType", _Report->ResultType);
}
}
// Determines if expression is immediate (completes within the current update/frame) or
// async (completes within the current update/frame or later).
//
// @TODO: SOL-1423, DetermineInvokeTime() re-traverses the expression tree, which could add up time wise
// (approaching on n^2) -- there should be a beter way to check this on the initial ProcessExpression()
EInvokeTime DetermineInvokeTime(const CSemanticProgram& Program) const { return (FindFirstAsyncSubExpr(Program) == nullptr) ? EInvokeTime::Immediate : EInvokeTime::Async; }
// Returns itself or the first async sub-expression or return nullptr if it and all its sub-expressions are immediate.
virtual const CExpressionBase* FindFirstAsyncSubExpr(const CSemanticProgram& Program) const { return nullptr; }
// Returns whether the expression may fail.
virtual bool CanFail(const CAstPackage* Package) const { return false; }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Type methods
UE_API virtual const CTypeBase* GetResultType(const CSemanticProgram& Program) const;
UE_API void SetResultType(const CTypeBase* InResultType);
UE_API void RefineResultType(const CTypeBase* RefinedResultType);
bool IsAnalyzed() const { return _Report.IsSet(); }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Comparison
static bool BaseCompare(const CExpressionBase& A, const CExpressionBase& B)
{
return
A.GetNodeType() == B.GetNodeType() &&
A._Report == B._Report;
}
virtual bool operator==(const CExpressionBase& Other) const = 0;
bool operator!=(const CExpressionBase& Other) const { return !(*this == Other); }
static bool IsSubExprEqual(const CExpressionBase* Lhs, const CExpressionBase* Rhs);
static bool IsSubExprEqual(const CExpressionBase& Lhs, const CExpressionBase& Rhs);
static bool IsSubExprEqual(const TSPtr<CExpressionBase>& Lhs, const TSPtr<CExpressionBase>& Rhs);
static bool IsSubExprEqual(const TSRef<CExpressionBase>& Lhs, const TSRef<CExpressionBase>& Rhs);
static bool AreSubExprsEqual(const TSPtrArray<CExpressionBase>& Lhs, const TSPtrArray<CExpressionBase>& Rhs);
static bool AreSubExprsEqual(const TArray<TSPtr<CExpressionBase>>& Lhs, const TArray<TSPtr<CExpressionBase>>& Rhs);
const CTypeBase* IrGetResultType() const { return _Report ? _Report->ResultType : nullptr; }
void IrSetResultType(const CTypeBase* TypeBase)
{
if (TypeBase)
{
_Report = SAnalysisResult{ TypeBase };
}
else
{
_Report.Reset();
}
}
protected:
// Analysis Results
struct SAnalysisResult
{
bool operator==(const SAnalysisResult& Other) const { return ResultType == Other.ResultType; }
/** The type to which this node evaluates. */
const CTypeBase* ResultType;
};
TOptional<SAnalysisResult> _Report;
}; // CExpressionBase
/**
* Base for expressions that have an array of subexpressions
* Subclasses: CExprMakeArray, CExprMakeMap, CExprMakeTuple, CExprCodeBlock, CExprConcurrentBlockBase
*/
class CExprCompoundBase : public CExpressionBase
{
public:
// Methods
explicit CExprCompoundBase(int32_t ReserveSubExprNum, EVstMappingType VstMappingType = EVstMappingType::Ast)
: CExpressionBase(VstMappingType)
{
_SubExprs.Reserve(ReserveSubExprNum);
}
explicit CExprCompoundBase(TSPtrArray<CExpressionBase>&& SubExprs, EVstMappingType VstMappingType = EVstMappingType::Ast)
: CExpressionBase(VstMappingType)
, _SubExprs(Move(SubExprs))
{}
explicit CExprCompoundBase(TSPtr<CExpressionBase>&& SubExpr1, TSPtr<CExpressionBase>&& SubExpr2)
: CExprCompoundBase(2)
{
AppendSubExpr(Move(SubExpr1));
AppendSubExpr(Move(SubExpr2));
}
CExprCompoundBase() = default;
bool IsEmpty() const { return _SubExprs.IsEmpty(); }
int32_t SubExprNum() const { return _SubExprs.Num(); }
const uLang::CExpressionBase* GetLastSubExpr() const { return _SubExprs.Last(); }
const TSPtrArray<CExpressionBase>& GetSubExprs() const { return _SubExprs; }
TSPtrArray<CExpressionBase>& GetSubExprs() { return _SubExprs; }
TSPtrArray<CExpressionBase>&& TakeSubExprs() { return Move(_SubExprs); }
void AppendSubExpr(TSPtr<CExpressionBase> SubExpr) { _SubExprs.Add(Move(SubExpr)); }
void PrependSubExpr(TSPtr<CExpressionBase> SubExpr) { _SubExprs.Insert(Move(SubExpr), 0); }
void SetSubExprs(TSPtrArray<CExpressionBase> AnalyzedExprs) { _SubExprs = Move(AnalyzedExprs); }
void ReplaceSubExpr(TSPtr<CExpressionBase> SubExpr, int32_t Index)
{
ULANG_ASSERTF(Index >= 0 && Index < _SubExprs.Num(), "Replacing invalid subexpression index");
_SubExprs.ReplaceAt(Move(SubExpr), Index);
}
UE_API virtual bool CanFail(const CAstPackage* Package) const override;
UE_API virtual const CExpressionBase* FindFirstAsyncSubExpr(const CSemanticProgram& Program) const override;
virtual void VisitChildren(SAstVisitor& Visitor) const override { Visitor.VisitArray("SubExprs", _SubExprs); }
UE_API virtual bool operator==(const CExpressionBase& Other) const override;
protected:
// Internal data
TSPtrArray<CExpressionBase> _SubExprs;
};
/**
* Base class of binary operators.
*/
class CExprBinaryOp : public CExpressionBase
{
private:
// Operands
TSPtr<CExpressionBase> _Lhs;
TSPtr<CExpressionBase> _Rhs;
public:
const TSPtr<CExpressionBase>& Lhs() const { return _Lhs; }
const TSPtr<CExpressionBase>& Rhs() const { return _Rhs; }
TSPtr<CExpressionBase>&& TakeRhs() { return Move(_Rhs); }
void SetLhs(TSPtr<CExpressionBase>&& NewLhs) { _Lhs = Move(NewLhs); }
void SetRhs(TSPtr<CExpressionBase>&& NewRhs) { _Rhs = Move(NewRhs); }
CExprBinaryOp(TSPtr<CExpressionBase>&& Lhs, TSPtr<CExpressionBase>&& Rhs) : _Lhs(Move(Lhs)), _Rhs(Move(Rhs)) {}
virtual const CExpressionBase* FindFirstAsyncSubExpr(const CSemanticProgram& Program) const override { const CExpressionBase* AsyncExpr = _Lhs->FindFirstAsyncSubExpr(Program); return AsyncExpr ? AsyncExpr : _Rhs->FindFirstAsyncSubExpr(Program); }
virtual void VisitChildren(SAstVisitor& Visitor) const override { Visitor.Visit("Lhs", _Lhs); Visitor.Visit("Rhs", _Rhs); }
};
// Note - if these subclasses of CExpressionBase become more sophisticated they should
// probably be moved to their own files.
/**
* Expression for external{} macro used in digests - should never reach the code generator
*/
class CExprExternal : public CExpressionBase
{
public:
// Methods
UE_API explicit CExprExternal(const CSemanticProgram& Program);
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::External; }
virtual CUTF8String GetErrorDesc() const override { return "external{}"; }
virtual bool operator==(const CExpressionBase& Other) const override { return Other.GetNodeType() == EAstNodeType::External; }
};
/**
* Logic literal - true/false
**/
class CExprLogic : public CExpressionBase
{
public:
bool _Value;
UE_API explicit CExprLogic(const CSemanticProgram& Program, bool Value);
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Literal_Logic; }
virtual CUTF8String GetErrorDesc() const override { return _Value ? "true" : "false"; }
virtual bool operator==(const CExpressionBase& Other) const override { return BaseCompare(*this, Other) && _Value == static_cast<const CExprLogic&>(Other)._Value; }
virtual void VisitImmediates(SAstVisitor& Visitor) const override { CExpressionBase::VisitImmediates(Visitor); Visitor.VisitImmediate("Value", _Value); }
};
/**
* Integer literal - 42, 0, -123, 123_456_789, 0x12fe, 0b101010
*/
class CExprNumber : public CExpressionBase
{
private:
union
{
Integer _IntValue;
Float _FloatValue;
};
bool _bIsFloat : 1;
public:
ULANG_FORCEINLINE explicit CExprNumber()
: _IntValue(0)
, _bIsFloat(false)
{}
UE_API explicit CExprNumber(CSemanticProgram&, Integer);
UE_API explicit CExprNumber(CSemanticProgram&, Float);
bool IsFloat() const { return _bIsFloat; }
Integer GetIntValue() const { ULANG_ASSERTF(!_bIsFloat, "Float number being treated as integer."); return _IntValue; }
UE_API void SetIntValue(CSemanticProgram&, Integer);
Float GetFloatValue() const { ULANG_ASSERTF( _bIsFloat, "Int number being treated as float"); return _FloatValue; }
UE_API void SetFloatValue(CSemanticProgram&, Float);
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Literal_Number; }
virtual CUTF8String GetErrorDesc() const override { return _bIsFloat ? "float literal" : "integer literal"; }
virtual bool operator==(const CExpressionBase& Other) const override {
return BaseCompare(*this, Other) && this->_IntValue == static_cast<const CExprNumber&>(Other)._IntValue;
}
virtual void VisitImmediates(SAstVisitor& Visitor) const override
{
CExpressionBase::VisitImmediates(Visitor);
if (_bIsFloat)
{
Visitor.VisitImmediate("FloatValue", _FloatValue);
}
else
{
Visitor.VisitImmediate("IntValue", _IntValue);
}
}
};
/**
* Character literal - 'H' '\n' '{0o00}' '{0u1f600}'
**/
class CExprChar : public CExpressionBase
{
public:
enum class EType
{
UTF8CodeUnit,
UnicodeCodePoint
};
uint32_t _CodePoint;
EType _Type;
explicit CExprChar(uint32_t CodePoint, EType Type)
: _CodePoint(CodePoint)
, _Type(Type)
{
if(_Type == EType::UTF8CodeUnit)
{
ULANG_ASSERTF(_CodePoint <= 0xFF, "utf8 code units must be <= 0xFF");
}
}
CUTF8String AsString() const
{
switch (_Type)
{
case CExprChar::EType::UTF8CodeUnit:
{
const UTF8Char CodeUnit = {static_cast<UTF8Char>(_CodePoint)};
return CUTF8StringView(&CodeUnit, &CodeUnit + 1);
}
case CExprChar::EType::UnicodeCodePoint:
{
SUTF8CodePoint Utf8 = CUnicode::EncodeUTF8(_CodePoint);
return CUTF8StringView(Utf8.Units, Utf8.Units + Utf8.NumUnits);
}
default:
ULANG_UNREACHABLE();
}
}
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Literal_Char; }
virtual CUTF8String GetErrorDesc() const override { return "char literal"; }
virtual bool operator==(const CExpressionBase& Other) const override { return Other.GetNodeType() == EAstNodeType::Literal_Char && _CodePoint == static_cast<const CExprChar&>(Other)._CodePoint; }
virtual void VisitImmediates(SAstVisitor& Visitor) const override { CExpressionBase::VisitImmediates(Visitor); Visitor.VisitImmediate("CodePoint", static_cast<int64_t>(_CodePoint)); }
};
/**
* String literal - "Hello, world!", "Line 1\nLine2"
**/
class CExprString : public CExpressionBase
{
public:
// Note that in the future this (or a related class) may include an array of substrings and sub-expressions for string interpolation.
// Ready to use string with any escaped characters translated
CUTF8String _String;
explicit CExprString(CUTF8String String)
: _String(Move(String)) {}
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Literal_String; }
virtual CUTF8String GetErrorDesc() const override { return "string literal"; }
virtual bool operator==(const CExpressionBase& Other) const override { return Other.GetNodeType() == EAstNodeType::Literal_String && _String == static_cast<const CExprString&>(Other)._String; }
virtual void VisitImmediates(SAstVisitor& Visitor) const override { CExpressionBase::VisitImmediates(Visitor); Visitor.VisitImmediate("String", _String); }
};
/**
* Path literal - /unrealengine.com/UnrealEngine
**/
class CExprPath : public CExpressionBase
{
public:
// Ready to use path with any escaped characters translated
CUTF8String _Path;
explicit CExprPath(CUTF8String Path)
: _Path(Move(Path)) {}
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Literal_Path; }
virtual CUTF8String GetErrorDesc() const override { return "path literal"; }
virtual bool operator==(const CExpressionBase& Other) const override { return Other.GetNodeType() == EAstNodeType::Literal_Path && _Path == static_cast<const CExprPath&>(Other)._Path; }
virtual void VisitImmediates(SAstVisitor& Visitor) const override { CExpressionBase::VisitImmediates(Visitor); Visitor.VisitImmediate("Path", _Path); }
};
/**
* Expression that evaluates to the path of the current scope, plus a given symbol, semantic analysis replaces this node with a CExprString
**/
class CExprPathPlusSymbol : public CExpressionBase
{
public:
const CSymbol _Symbol;
explicit CExprPathPlusSymbol(const CSymbol& Symbol)
: _Symbol(Symbol) {}
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::PathPlusSymbol; }
virtual CUTF8String GetErrorDesc() const override { return "path plus symbol"; }
virtual bool operator==(const CExpressionBase& Other) const override { return Other.GetNodeType() == EAstNodeType::PathPlusSymbol && _Symbol == static_cast<const CExprPathPlusSymbol&>(Other)._Symbol; }
};
/**
* The base class of identifiers expressions.
*/
class CExprIdentifierBase : public CExpressionBase
{
public:
CExprIdentifierBase(TSPtr<CExpressionBase>&& Context = nullptr, TSPtr<CExpressionBase>&& Qualifier = nullptr)
: _Context(Move(Context)), _Qualifier(Move(Qualifier))
{}
const TSPtr<CExpressionBase>& Context() const { return _Context; }
const TSPtr<CExpressionBase>& Qualifier() const { return _Qualifier; }
TSPtr<CExpressionBase>&& TakeContext() { return Move(_Context); }
TSPtr<CExpressionBase>&& TakeQualifier() { return Move(_Qualifier); }
void SetContext(TSPtr<CExpressionBase> Context)
{
_Context = Move(Context);
}
void SetQualifier(TSPtr<CExpressionBase> Qualifier)
{
_Qualifier = Move(Qualifier);
}
// CAstNode interface.
virtual bool MayHaveAttributes() const override { return true; }
// CExpressionBase interface.
virtual bool CanFail(const CAstPackage* Package) const override { return _Context.IsValid() && _Context->CanFail(Package); }
virtual const CExpressionBase* FindFirstAsyncSubExpr(const CSemanticProgram& Program) const override
{
const CExpressionBase* AsyncExpr = nullptr;
if (_Context) { AsyncExpr = _Context->FindFirstAsyncSubExpr(Program); }
if (!AsyncExpr && _Qualifier) { AsyncExpr = _Qualifier->FindFirstAsyncSubExpr(Program); }
return AsyncExpr;
}
virtual bool operator==(const CExpressionBase& Other) const override
{
return CExpressionBase::BaseCompare(*this, Other)
&& _Context == static_cast<const CExprIdentifierBase&>(Other)._Context
&& _Qualifier == static_cast<const CExprIdentifierBase&>(Other)._Qualifier;
}
virtual void VisitChildren(SAstVisitor& Visitor) const override
{
Visitor.Visit("Context", _Context);
}
/// This is specifically named as such to avoid shadowing other virtual methods (such as on `CNominalType`).
virtual const CDefinition* IdentifierDefinition() const
{
return nullptr;
}
/// This node contains an identifier
virtual const CExprIdentifierBase* AsIdentifierBase() const override { return this; }
private:
TSPtr<CExpressionBase> _Context;
TSPtr<CExpressionBase> _Qualifier;
};
/**
* Enumerator - #GlobalEnum.enumeration, #.enumeration, MyType#Confirm.yes, #Confirm.yes,
* #.yes, MyType@set_size#size.medium, #size.medium, #.medium, #position.upper, #.upper
**/
class CExprEnumLiteral : public CExprIdentifierBase
{
public:
// Specific enumerator this represents - note that it also contains a pointer to its enumeration type.
const CEnumerator* _Enumerator;
ULANG_FORCEINLINE explicit CExprEnumLiteral(const CEnumerator* Enumerator, TSPtr<CExpressionBase>&& Context = nullptr, TSPtr<CExpressionBase>&& Qualifier = nullptr)
: CExprIdentifierBase(Move(Context), Move(Qualifier))
, _Enumerator(Enumerator)
{}
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Literal_Enum; }
virtual CUTF8String GetErrorDesc() const override { return "enumerator"; }
UE_API virtual const CTypeBase* GetResultType(const CSemanticProgram& Program) const override;
virtual bool operator==(const CExpressionBase& Other) const override { return CExprIdentifierBase::operator==(Other) && _Enumerator == static_cast<const CExprEnumLiteral&>(Other)._Enumerator; }
UE_API virtual void VisitImmediates(SAstVisitor& Visitor) const override;
virtual const CDefinition* IdentifierDefinition() const override;
};
/**
* Type expression - type{<expr>}
*/
class CExprType : public CExpressionBase
{
public:
const TSRef<CExpressionBase> _AbstractValue;
CExprType(TSRef<CExpressionBase>&& AbstractValue, const CTypeType& TypeType)
: _AbstractValue(Move(AbstractValue))
{
SetResultType(&TypeType);
}
const CTypeType* GetTypeType() const
{
return static_cast<const CTypeType*>(_Report->ResultType);
}
const CTypeBase* GetType() const
{
const CTypeType* TypeType = GetTypeType();
return TypeType->PositiveType();
}
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Literal_Type; }
virtual CUTF8String GetErrorDesc() const override { return "type"; }
virtual bool operator==(const CExpressionBase& Other) const override { return GetNodeType() == Other.GetNodeType() && IsSubExprEqual(_AbstractValue, static_cast<const CExprType&>(Other)._AbstractValue); }
virtual void VisitChildren(SAstVisitor& Visitor) const override { Visitor.Visit("AbstractValue", _AbstractValue); }
};
/**
* Function literal - a=>b or function(a){b}
*/
class CExprFunctionLiteral : public CExpressionBase
{
public:
CExprFunctionLiteral(TSRef<CExpressionBase>&& Domain, TSRef<CExpressionBase>&& Range)
: _Domain(Move(Domain))
, _Range(Move(Range))
{}
const TSRef<CExpressionBase>& Domain() const { return _Domain; }
const TSRef<CExpressionBase>& Range () const { return _Range ; }
void SetDomain(TSRef<CExpressionBase>&& NewDomain) { _Domain = Move(NewDomain); }
void SetRange(TSRef<CExpressionBase>&& NewRange ) { _Range = Move(NewRange) ; }
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Literal_Function; }
virtual CUTF8String GetErrorDesc() const override { return "function literal"; }
virtual bool operator==(const CExpressionBase& Other) const override
{
return GetNodeType() == Other.GetNodeType()
&& IsSubExprEqual(_Domain, static_cast<const CExprFunctionLiteral&>(Other)._Domain)
&& IsSubExprEqual(_Range, static_cast<const CExprFunctionLiteral&>(Other)._Range);
}
virtual void VisitChildren(SAstVisitor& Visitor) const override { Visitor.Visit("Domain", _Domain); Visitor.Visit("Range", _Range); }
private:
TSRef<CExpressionBase> _Domain;
TSRef<CExpressionBase> _Range;
};
/**
* Access to the instance the current function is being invoked on.
**/
class CExprSelf : public CExprIdentifierBase
{
public:
CExprSelf(const CTypeBase* Type, TSPtr<CExpressionBase>&& Qualifier = nullptr)
: CExprIdentifierBase(nullptr, Move(Qualifier))
{
SetResultType(Type);
}
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Identifier_Self; }
virtual CUTF8String GetErrorDesc() const override { return "'Self'"; }
virtual const CDefinition* IdentifierDefinition() const override
{
// TODO: (yiliang.siew) Implement this.
return nullptr;
}
};
/// Represents the `(local:) qualifier`.
class CExprLocal : public CExprIdentifierBase
{
public:
CExprLocal(const CScope& Scope) : CExprIdentifierBase(), _Scope(Scope)
{}
virtual EAstNodeType GetNodeType() const override
{
return EAstNodeType::Identifier_Local;
}
virtual CUTF8String GetErrorDesc() const override
{
return "'(local:)'";
}
const CScope& GetScope() const
{
return _Scope;
}
private:
const CScope& _Scope;
};
/**
* Represents a name of a a compiler built-in macro; e.g. option, array.
* These should always be resolved by analysis and never make their way into code gen.
**/
class CExprIdentifierBuiltInMacro : public CExprIdentifierBase
{
public:
const CSymbol _Symbol;
CExprIdentifierBuiltInMacro(const CSymbol Symbol, const CTypeBase* Type)
: CExprIdentifierBase(nullptr, nullptr)
, _Symbol(Symbol)
{
SetResultType(Type);
}
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Identifier_BuiltInMacro; }
virtual CUTF8String GetErrorDesc() const override { return _Symbol.AsStringView(); }
virtual bool operator==(const CExpressionBase& Other) const override { return CExprIdentifierBase::operator==(Other) && _Symbol == static_cast<const CExprIdentifierBuiltInMacro&>(Other)._Symbol; }
virtual void VisitImmediates(SAstVisitor& Visitor) const override { CExpressionBase::VisitImmediates(Visitor); Visitor.VisitImmediate("Symbol", _Symbol.AsStringView()); }
};
/**
* An unresolved type identifier that is produced by desugaring, and consumed by analysis.
**/
class CExprIdentifierUnresolved : public CExprIdentifierBase
{
public:
const CSymbol _Symbol;
// Used for some internal compiler-generated code that is
// allowed to lookup identifiers that are otherwise restricted
// (private, internal, ...)
bool _bAllowUnrestrictedAccess;
const bool _bAllowReservedOperators;
CExprIdentifierUnresolved(const CSymbol& Symbol, TSPtr<CExpressionBase>&& Context = nullptr, TSPtr<CExpressionBase>&& Qualifier = nullptr, bool bAllowReservedOperators = false)
: CExprIdentifierBase( Move(Context), Move(Qualifier))
, _Symbol(Symbol)
, _bAllowUnrestrictedAccess(false)
, _bAllowReservedOperators(bAllowReservedOperators)
{}
// Use with extreme caution! Setting this allows this identifier lookup to succeed where it
// would otherwise fail due to not having permission
void GrantUnrestrictedAccess() { _bAllowUnrestrictedAccess = true; }
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Identifier_Unresolved; }
virtual bool MayHaveAttributes() const override { return true; }
virtual CUTF8String GetErrorDesc() const override { return _Symbol.AsString(); }
virtual bool operator==(const CExpressionBase& Other) const override { return CExprIdentifierBase::operator==(Other) && _Symbol == static_cast<const CExprIdentifierUnresolved&>(Other)._Symbol; }
virtual void VisitImmediates(SAstVisitor& Visitor) const override { CExpressionBase::VisitImmediates(Visitor); Visitor.VisitImmediate("Symbol", _Symbol.AsStringView()); }
};
/**
* Type identifier - MyType
**/
class CExprIdentifierClass : public CExprIdentifierBase
{
public:
UE_API CExprIdentifierClass(const CTypeType* Type, TSPtr<CExpressionBase>&& Context = nullptr, TSPtr<CExpressionBase>&& Qualifier = nullptr);
UE_API const CTypeType* GetTypeType(const CSemanticProgram& Program) const;
UE_API const CClass* GetClass(const CSemanticProgram& Program) const;
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Identifier_Class; }
UE_API virtual CUTF8String GetErrorDesc() const override;
};
/**
* Module identifier
**/
class CExprIdentifierModule : public CExprIdentifierBase
{
public:
UE_API CExprIdentifierModule(const CModule* Module, TSPtr<CExpressionBase>&& Context = nullptr, TSPtr<CExpressionBase>&& Qualifier = nullptr);
UE_API CModule const* GetModule(const CSemanticProgram& Program) const;
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Identifier_Module; }
virtual CUTF8String GetErrorDesc() const override { return "module identifier"; }
};
/**
* Module alias identifier
**/
class CExprIdentifierModuleAlias : public CExprIdentifierBase
{
public:
const CModuleAlias& _ModuleAlias;
CExprIdentifierModuleAlias(const CModuleAlias& ModuleAlias, TSPtr<CExpressionBase>&& Context = nullptr, TSPtr<CExpressionBase>&& Qualifier = nullptr)
: CExprIdentifierBase(Move(Context), Move(Qualifier))
, _ModuleAlias(ModuleAlias)
{}
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Identifier_ModuleAlias; }
virtual CUTF8String GetErrorDesc() const override { return "module alias identifier"; }
};
/**
* Enum identifier
* @jira SOL-1013 : Shouldn't this inherit from CExprIdentifierClass?
**/
class CExprEnumerationType : public CExprIdentifierBase
{
public:
CExprEnumerationType(const CTypeType* TypeType, TSPtr<CExpressionBase>&& Context = nullptr, TSPtr<CExpressionBase>&& Qualifier = nullptr)
: CExprIdentifierBase(Move(Context), Move(Qualifier))
{
SetResultType(TypeType);
}
UE_API const CTypeType* GetTypeType(const CSemanticProgram& Program) const;
UE_API const CEnumeration* GetEnumeration(const CSemanticProgram& Program) const;
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Identifier_Enum; }
virtual CUTF8String GetErrorDesc() const override { return "enum type identifier"; }
};
/**
* Interface identifier
* @jira SOL-1013 : Shouldn't this inherit from CExprIdentifierClass?
**/
class CExprInterfaceType : public CExprIdentifierBase
{
public:
// Identified type
CExprInterfaceType(const CTypeType* TypeType, TSPtr<CExpressionBase>&& Context = nullptr, TSPtr<CExpressionBase>&& Qualifier = nullptr)
: CExprIdentifierBase(Move(Context), Move(Qualifier))
{
SetResultType(TypeType);
}
const CTypeType* GetTypeType(const CSemanticProgram& Program) const { return &GetResultType(Program)->GetNormalType().AsChecked<CTypeType>(); }
UE_API const CInterface* GetInterface(const CSemanticProgram& Program) const;
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Identifier_Interface; }
virtual CUTF8String GetErrorDesc() const override { return "interface type identifier"; }
};
/**
* Local or class identifier - temp, arg, captured
**/
class CExprIdentifierData : public CExprIdentifierBase
{
public:
// The variable this expression is referring to
const CDataDefinition& _DataDefinition;
UE_API CExprIdentifierData(const CSemanticProgram& Program, const CDataDefinition& DataDefinition, TSPtr<CExpressionBase>&& Context = nullptr, TSPtr<CExpressionBase>&& Qualifier = nullptr);
virtual const CSymbol& GetName() const { return _DataDefinition.GetName(); }
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Identifier_Data; }
virtual CUTF8String GetErrorDesc() const override { return _DataDefinition.AsNameStringView(); }
UE_API virtual const CTypeBase* GetResultType(const CSemanticProgram& Program) const override;
virtual bool operator==(const CExpressionBase& Other) const override { return CExprIdentifierBase::operator==(Other) && &_DataDefinition == &static_cast<const CExprIdentifierData&>(Other)._DataDefinition; }
virtual void VisitImmediates(SAstVisitor& Visitor) const override { CExpressionBase::VisitImmediates(Visitor); Visitor.VisitImmediate("DataDefinition", _DataDefinition); }
};
/**
* Access to a type alias
*/
class CExprIdentifierTypeAlias : public CExprIdentifierBase
{
public:
// The type alias this expression is referring to
const CTypeAlias& _TypeAlias;
UE_API CExprIdentifierTypeAlias(const CTypeAlias& TypeAlias, TSPtr<CExpressionBase>&& Context = nullptr, TSPtr<CExpressionBase>&& Qualifier = nullptr);
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Identifier_TypeAlias; }
virtual CUTF8String GetErrorDesc() const override { return "type alias identifier"; }
UE_API virtual const CTypeBase* GetResultType(const CSemanticProgram& Program) const override;
virtual bool operator==(const CExpressionBase& Other) const override { return CExprIdentifierBase::operator==(Other) && &_TypeAlias == &static_cast<const CExprIdentifierTypeAlias&>(Other)._TypeAlias; }
UE_API virtual void VisitImmediates(SAstVisitor& Visitor) const override;
};
/**
* Access to a type variable
*/
class CExprIdentifierTypeVariable : public CExprIdentifierBase
{
public:
// The type variable this expression is referring to
const CTypeVariable& _TypeVariable;
UE_API CExprIdentifierTypeVariable(const CTypeVariable& TypeVariable, TSPtr<CExpressionBase>&& Context = nullptr, TSPtr<CExpressionBase>&& Qualifier = nullptr);
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Identifier_TypeVariable; }
virtual CUTF8String GetErrorDesc() const override { return "type variable identifier"; }
virtual bool operator==(const CExpressionBase& Other) const override { return CExprIdentifierBase::operator==(Other) && &_TypeVariable == &static_cast<const CExprIdentifierTypeVariable&>(Other)._TypeVariable; }
UE_API virtual void VisitImmediates(SAstVisitor& Visitor) const override;
};
/**
* Access to instance function members
**/
class CExprIdentifierFunction : public CExprIdentifierBase
{
public:
const CFunction& _Function;
// `CFlowType`s created as part of instantiating `_Function`.
TArray<SInstantiatedTypeVariable> _InstantiatedTypeVariables;
const CTypeBase* _ConstructorNegativeReturnType;
const bool _bSuperQualified;
CExprIdentifierFunction(
const CFunction& Function,
const CTypeBase* ResultType,
TSPtr<CExpressionBase>&& Context = nullptr,
TSPtr<CExpressionBase>&& Qualifier = nullptr)
: CExprIdentifierFunction(Function, {}, ResultType, nullptr, Move(Context), Move(Qualifier), false)
{}
UE_API CExprIdentifierFunction(
const CFunction& Function,
TArray<SInstantiatedTypeVariable> InstTypeVariables,
const CTypeBase* ResultType,
const CTypeBase* ConstructorNegativeReturnType,
TSPtr<CExpressionBase>&& Context,
TSPtr<CExpressionBase>&& Qualifier,
bool bSuperQualified);
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Identifier_Function; }
virtual CUTF8String GetErrorDesc() const override { return "function identifier"; }
virtual bool operator==(const CExpressionBase& Other) const override { return CExprIdentifierBase::operator==(Other) && &_Function == &static_cast<const CExprIdentifierFunction&>(Other)._Function; }
UE_API virtual void VisitImmediates(SAstVisitor& Visitor) const override;
};
/**
* An overloaded function identifier that hasn't been resolved to a specific overload.
*/
class CExprIdentifierOverloadedFunction : public CExprIdentifierBase
{
public:
const TArray<const CFunction*> _FunctionOverloads;
bool _bConstructor;
const CSymbol _Symbol;
const CTypeBase* _TypeOverload;
// Used for some internal compiler-generated code that is
// allowed to lookup identifiers that are otherwise restricted
// (private, internal, ...)
bool _bAllowUnrestrictedAccess;
UE_API CExprIdentifierOverloadedFunction(
TArray<const CFunction*>&& OverloadedFunctions,
bool bConstructor,
const CSymbol Symbol,
const CTypeBase* OverloadedType,
TSPtr<CExpressionBase>&& Context,
TSPtr<CExpressionBase>&& Qualifier,
const CTypeBase* Type);
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Identifier_OverloadedFunction; }
virtual CUTF8String GetErrorDesc() const override { return "overloaded function identifier"; }
virtual bool operator==(const CExpressionBase& Other) const override
{
return CExprIdentifierBase::operator==(Other)
&& _FunctionOverloads == static_cast<const CExprIdentifierOverloadedFunction&>(Other)._FunctionOverloads
&& _TypeOverload == static_cast<const CExprIdentifierOverloadedFunction&>(Other)._TypeOverload;
}
UE_API virtual void VisitImmediates(SAstVisitor& Visitor) const override;
};
/**
* Represents all definitions (and assignments) supported by Verse.
* They are:
* element:valueDomain=value e.g. x:int=5 e.g. f(x:int):int=x*x
* element:valueDomain e.g. x:int e.g. f(x:int):int
* element=value e.g. x=5 e.g. f(x:int)=x*x
*/
class CExprDefinition : public CExpressionBase
{
public:
CExprDefinition(TSPtr<CExpressionBase>&& Element, TSPtr<CExpressionBase>&& ValueDomain, TSPtr<CExpressionBase>&& Value, EVstMappingType VstMappingType = EVstMappingType::Ast)
: CExpressionBase(VstMappingType)
{
if (Element) { SetElement(Move(Element.AsRef())); }
if (ValueDomain) { SetValueDomain(Move(ValueDomain.AsRef())); }
if (Value) { SetValue(Move(Value.AsRef())); }
}
explicit CExprDefinition(EVstMappingType VstMappingType = EVstMappingType::Ast) : CExpressionBase(VstMappingType) {}
const TSPtr<CExpressionBase>& Element() const { return _Element; }
void SetElement(TSRef<CExpressionBase>&& Element) { _Element = Move(Element); }
TSPtr<CExpressionBase> TakeElement() { return Move(_Element); }
void SetName(CSymbol Name) { _Name = Name; }
CSymbol GetName() const { return _Name; }
bool IsNamed() const { return !_Name.IsNull(); }
const TSPtr<CExpressionBase>& ValueDomain() const { return _ValueDomain; }
void SetValueDomain(TSRef<CExpressionBase>&& ValueDomain) { _ValueDomain = Move(ValueDomain); }
TSPtr<CExpressionBase> TakeValueDomain() { return Move(_ValueDomain); }
const TSPtr<CExpressionBase>& Value() const { return _Value; }
void SetValue(TSRef<CExpressionBase>&& Value) { _Value = Move(Value); }
TSPtr<CExpressionBase> TakeValue() { return Move(_Value); }
virtual bool CanBePathSegment(const TMacroSymbols& MacroSymbols) const override
{
return Value() && Value()->CanBePathSegment(MacroSymbols);
}
// CAstNode interface.
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Definition; }
virtual CUTF8String GetErrorDesc() const override { return CUTF8String("definition"); }
virtual void VisitChildren(SAstVisitor& Visitor) const override { Visitor.Visit("Element", _Element); Visitor.Visit("ValueDomain", _ValueDomain); Visitor.Visit("Value", _Value); }
virtual bool MayHaveAttributes() const override { return true; }
// CExpressionBase interface.
UE_API virtual bool operator==(const CExpressionBase& Other) const override;
UE_API virtual bool CanFail(const CAstPackage* Package) const override;
UE_API virtual const CExpressionBase* FindFirstAsyncSubExpr(const CSemanticProgram& Program) const override;
protected:
TSPtr<CExpressionBase> _Element;
TSPtr<CExpressionBase> _ValueDomain;
TSPtr<CExpressionBase> _Value;
CSymbol _Name; // If non-null, then usage requires being ?named and presence of `_Value` indicates that it has a default
};
enum class EMacroClauseTag : uint32_t
{
None = 0x1 << 0,
Of = 0x1 << 1,
Do = 0x1 << 2
};
constexpr EMacroClauseTag operator| (EMacroClauseTag A, EMacroClauseTag B) { return static_cast<EMacroClauseTag>(static_cast<uint32_t>(A) | static_cast<uint32_t>(B)); }
constexpr bool HasAnyTags(EMacroClauseTag A, EMacroClauseTag B) { return 0 != (static_cast<uint32_t>(A) & static_cast<uint32_t>(B)); }
constexpr bool HasAllTags(EMacroClauseTag A, EMacroClauseTag RequiredTags)
{
return RequiredTags == static_cast<EMacroClauseTag>(static_cast<uint32_t>(A) & static_cast<uint32_t>(RequiredTags));
}
inline const char* MacroClauseTagAsCString(EMacroClauseTag Tag)
{
switch(Tag)
{
case EMacroClauseTag::None: return "None";
case EMacroClauseTag::Of: return "Of";
case EMacroClauseTag::Do: return "Do";
default: ULANG_UNREACHABLE();
};
}
inline const char* MacroClauseFormAsCString(Verse::Vst::Clause::EForm Form)
{
switch(Form)
{
case Verse::Vst::Clause::EForm::Synthetic: return "Synthetic";
case Verse::Vst::Clause::EForm::NoSemicolonOrNewline: return "NoSemicolonOrNewline";
case Verse::Vst::Clause::EForm::HasSemicolonOrNewline: return "HasSemicolonOrNewline";
case Verse::Vst::Clause::EForm::IsAppendAttributeHolder: return "IsAppendAttributeHolder";
case Verse::Vst::Clause::EForm::IsPrependAttributeHolder: return "IsPrependAttributeHolder";
default: ULANG_UNREACHABLE();
};
}
/** A macro call of the form m1{}, m2(){}, or more generally m(){}keyword_1{}keyword_2{}...keyword_N{} */
class CExprMacroCall : public CExpressionBase
{
public:
/** A macro is an identifier followed by any number of tagged clauses. This class represents a single clause. */
class CClause
{
public:
using EForm = Verse::Vst::Clause::EForm;
CClause(EMacroClauseTag Tag, EForm Form, TArray<TSRef<CExpressionBase>>&& Exprs)
: _Tag(Tag)
, _Form(Form)
, _Exprs(Move(Exprs))
{}
EMacroClauseTag Tag() const { return _Tag; }
EForm Form() const { return _Form; }
TArray<TSRef<CExpressionBase>> const & Exprs() const { return _Exprs; }
TArray<TSRef<CExpressionBase>> & Exprs() { return _Exprs; }
private:
EMacroClauseTag _Tag;
Verse::Vst::Clause::EForm _Form;
TArray<TSRef<CExpressionBase>> _Exprs;
};
public:
CExprMacroCall( TSRef<CExpressionBase>&& Name, int32_t NumClauses = 0 )
: _Name(Move(Name))
, _Clauses()
{
if (NumClauses != 0)
{
_Clauses.Reserve(NumClauses);
}
}
void AppendClause(CClause&& Clause)
{
_Clauses.Add(Move(Clause));
}
TSRef<CExpressionBase> const & Name() const { return _Name; }
TSRef<CExpressionBase> & Name() { return _Name; }
void SetName(TSRef<CExpressionBase>&& NewName) { _Name = Move(NewName); }
TSRef<CExpressionBase>&& TakeName() { return Move(_Name); }
TArray<CClause> const& Clauses() const { return _Clauses; }
TArray<CClause> & Clauses() { return _Clauses; }
TArray<CClause>&& TakeClauses() { return Move(_Clauses); }
virtual bool CanBePathSegment(const TMacroSymbols& MacroSymbols) const override {
CSymbol Symbol;
if (_Name->GetNodeType() == EAstNodeType::Identifier_BuiltInMacro) {
Symbol = static_cast<CExprIdentifierBuiltInMacro*>(_Name.Get())->_Symbol;
}
else if (_Name->GetNodeType() == EAstNodeType::Identifier_Unresolved)
{
Symbol = static_cast<CExprIdentifierUnresolved*>(_Name.Get())->_Symbol;
}
if (!Symbol.IsNull())
{
for (CSymbol MacroSymbol : MacroSymbols)
{
if (MacroSymbol == Symbol)
{
return true;
}
}
}
return false;
}
private:
// Inherited via CExpressionBase
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::MacroCall; }
virtual CUTF8String GetErrorDesc() const override { return "macro invocation"; }
virtual bool operator==(const CExpressionBase& Other) const override { return BaseCompare(*this,Other); }
virtual void VisitChildren(SAstVisitor& Visitor) const override
{
Visitor.Visit("Name", _Name);
Visitor.BeginArray("Clauses", _Clauses.Num());
for (const CClause& Clause : _Clauses)
{
Visitor.VisitArray("Exprs", Clause.Exprs());
}
Visitor.EndArray();
}
virtual void VisitImmediates(SAstVisitor& Visitor) const override
{
CExpressionBase::VisitImmediates(Visitor);
Visitor.BeginArray("Clauses", _Clauses.Num());
for (const CClause& Clause : _Clauses)
{
Visitor.VisitImmediate("Tag", MacroClauseTagAsCString(Clause.Tag()));
Visitor.VisitImmediate("Form", MacroClauseFormAsCString(Clause.Form()));
}
Visitor.EndArray();
}
private:
TSRef<CExpressionBase> _Name;
TArray<CClause> _Clauses;
};
/**
* Routine call - expr1.call(expr2, expr3)
**/
class CExprInvocation : public CExpressionBase
{
public:
enum class EBracketingStyle
{
Undefined,
Parentheses,
SquareBrackets,
};
EBracketingStyle _CallsiteBracketStyle = EBracketingStyle::Undefined;
template<typename TCallee, typename TArgument>
CExprInvocation(EBracketingStyle CallsiteBracketStyle, TCallee&& Callee, TArgument&& Argument)
: _CallsiteBracketStyle(CallsiteBracketStyle)
, _Callee(ForwardArg<TCallee>(Callee))
, _Argument(ForwardArg<TArgument>(Argument))
{}
template<typename TCallee, typename TArgument>
CExprInvocation(EBracketingStyle CallsiteBracketStyle,
TCallee&& Callee,
TArgument&& Argument,
const CFunctionType* ResolvedCalleeType,
const CTypeBase* ResultType)
: CExprInvocation(CallsiteBracketStyle, ForwardArg<TCallee>(Callee), ForwardArg<TArgument>(Argument))
{
SetResolvedCalleeType(ResolvedCalleeType);
SetResultType(ResultType);
}
explicit CExprInvocation(TSRef<CExpressionBase>&& Argument)
: _Argument(Move(Argument))
{}
CExprInvocation(CExprInvocation&& Rhs)
: _Callee(Move(Rhs._Callee))
, _Argument(Move(Rhs._Argument))
, _ResolvedCalleeType(Rhs._ResolvedCalleeType)
{}
const TSPtr<CExpressionBase>& GetCallee() const { return _Callee; }
TSPtr<CExpressionBase>&& TakeCallee() { return Move(_Callee); }
void SetCallee(TSPtr<CExpressionBase>&& Callee) { _Callee = Move(Callee); }
const TSPtr<CExpressionBase>& GetArgument() const { return _Argument; }
TSPtr<CExpressionBase>&& TakeArgument() { return Move(_Argument); }
void SetArgument(TSPtr<CExpressionBase>&& Arguments) { _Argument = Move(Arguments); }
UE_API const CFunctionType* GetResolvedCalleeType() const;
void SetResolvedCalleeType(const CFunctionType* ResolvedCalleeType) { _ResolvedCalleeType = ResolvedCalleeType; }
/// Get the function that this invocation calls
UE_API virtual const CExpressionBase* FindFirstAsyncSubExpr(const CSemanticProgram& Program) const override;
UE_API virtual bool CanFail(const CAstPackage* Package) const override;
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Invoke_Invocation; }
virtual CUTF8String GetErrorDesc() const override { return "invocation"; }
virtual void VisitChildren(SAstVisitor& Visitor) const override { Visitor.Visit("Callee", _Callee); Visitor.Visit("Argument", _Argument); }
virtual void VisitImmediates(SAstVisitor& Visitor) const override
{
CExpressionBase::VisitImmediates(Visitor);
const char* BracketStyleString;
switch(_CallsiteBracketStyle)
{
case EBracketingStyle::Undefined: BracketStyleString = "Undefined"; break;
case EBracketingStyle::Parentheses: BracketStyleString = "Parentheses"; break;
case EBracketingStyle::SquareBrackets: BracketStyleString = "SquareBrackets"; break;
default: ULANG_UNREACHABLE();
};
Visitor.VisitImmediate("CallsiteBracketStyle", BracketStyleString);
if (_ResolvedCalleeType)
{
Visitor.VisitImmediate("ResolvedCalleeType", _ResolvedCalleeType);
}
}
UE_API virtual bool operator==(const CExpressionBase& Other) const override;
private:
// Callee subexpression - The function to call.
TSPtr<CExpressionBase> _Callee;
// Argument - possibly a tuple of expressions, included named expressions
TSPtr<CExpressionBase> _Argument;
// More often than not, the function type could be inferred from _Callee, but in the case of generics,
// you want to store the function type of the resolved generic.
const CFunctionType* _ResolvedCalleeType{nullptr};
};
VERSECOMPILER_API const CExprIdentifierFunction* GetConstructorInvocationCallee(const CExprInvocation&);
VERSECOMPILER_API const CExprIdentifierFunction* GetConstructorInvocationCallee(const CExpressionBase&);
VERSECOMPILER_API bool IsConstructorInvocation(const CExprInvocation&);
VERSECOMPILER_API bool IsConstructorInvocation(const CExpressionBase&);
/**
* Tuple element access `TupleExpr(Idx)`
**/
class CExprTupleElement : public CExpressionBase
{
public:
// Expression that results in tuple to access element from
TSPtr<CExpressionBase> _TupleExpr;
// Index resolved from `_ElemIdxExpr`
Integer _ElemIdx;
// Expression used to determine index - currently must be an integer literal CExprNumber.
// `_ElemIdx` is resolved form. This is stored just to track source information in VST nodes.
TSPtr<CExpressionBase> _ElemIdxExpr;
CExprTupleElement(CExprInvocation& Invocation) : _TupleExpr(Invocation.TakeCallee()), _ElemIdx(-1) { Invocation.GetMappedVstNode()->AddMapping(this); }
CExprTupleElement(TSPtr<CExpressionBase> TupleExpr, Integer ElemIdx, const Verse::Vst::Node* MappedVstNode) : _TupleExpr(TupleExpr), _ElemIdx(ElemIdx) { _MappedVstNode = MappedVstNode; }
UE_API virtual bool CanFail(const CAstPackage* Package) const override;
virtual void VisitChildren(SAstVisitor& Visitor) const override { Visitor.Visit("TupleExpr", _TupleExpr); Visitor.Visit("ElemIdxExpr", _ElemIdxExpr); }
virtual void VisitImmediates(SAstVisitor& Visitor) const override { CExpressionBase::VisitImmediates(Visitor); Visitor.VisitImmediate("ElemIdx", _ElemIdx); }
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Invoke_TupleElement; }
virtual CUTF8String GetErrorDesc() const override { return "tuple element access"; }
UE_API virtual bool operator==(const CExpressionBase& Other) const override;
};
/**
* Assignment -- expr1 = expr2, expr1 := expr2, expr1 += expr2, etc.
*/
class CExprAssignment : public CExpressionBase
{
public:
using EOp = Verse::Vst::Assignment::EOp;
CExprAssignment(EOp Op, TSPtr<CExpressionBase>&& Lhs, TSPtr<CExpressionBase>&& Rhs)
: _Op(Op), _Lhs(Move(Lhs)), _Rhs(Move(Rhs))
{}
EOp Op() const { return _Op; }
const TSPtr<CExpressionBase>& Lhs() const { return _Lhs; }
const TSPtr<CExpressionBase>& Rhs() const { return _Rhs; }
TSPtr<CExpressionBase>&& TakeLhs() { return Move(_Lhs); }
TSPtr<CExpressionBase>&& TakeRhs() { return Move(_Rhs); }
void SetLhs(TSPtr<CExpressionBase>&& Lhs) { _Lhs = Move(Lhs); }
void SetRhs(TSPtr<CExpressionBase>&& Rhs) { _Rhs = Move(Rhs); }
//~ Begin CExpressionBase interface
virtual const CExpressionBase* FindFirstAsyncSubExpr(const CSemanticProgram& Program) const override { const CExpressionBase* AsyncExpr = _Lhs->FindFirstAsyncSubExpr(Program); return AsyncExpr ? AsyncExpr : _Rhs->FindFirstAsyncSubExpr(Program); }
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Assignment; }
virtual CUTF8String GetErrorDesc() const override { return "assignment"; }
virtual bool CanFail(const CAstPackage* Package) const override { return _Lhs->CanFail(Package) || _Rhs->CanFail(Package); }
virtual void VisitChildren(SAstVisitor& Visitor) const override { Visitor.Visit("Lhs", _Lhs); Visitor.Visit("Rhs", _Rhs); }
virtual void VisitImmediates(SAstVisitor& Visitor) const override { CExpressionBase::VisitImmediates(Visitor); Visitor.VisitImmediate("Op", Verse::Vst::AssignmentOpAsCString(_Op)); }
UE_API virtual bool operator==(const CExpressionBase& Other) const override;
//~ End CExpressionBase interface
private:
const EOp _Op;
TSPtr<CExpressionBase> _Lhs;
TSPtr<CExpressionBase> _Rhs;
};
struct SAssignmentLhsIdentifier
{
TSPtr<CExprPointerToReference> PointerToReference;
TSPtr<CExprIdentifierData> IdentifierData;
};
VERSECOMPILER_API TOptional<SAssignmentLhsIdentifier> IdentifierOfAssignmentLhs(const CExprAssignment* Assignment /* can be null */);
VERSECOMPILER_API bool HasImplicitClassSelf(const CExprIdentifierData* Expr /* can be null */);
VERSECOMPILER_API bool IsClassMemberAccess(const CExprIdentifierData* Expr /* can be null */);
/**
* Base class of unary operators.
*/
class CExprUnaryOp : public CExpressionBase
{
public:
explicit CExprUnaryOp(TSPtr<CExpressionBase>&& Operand, EVstMappingType VstMappingType = EVstMappingType::Ast)
: CExpressionBase(VstMappingType)
{
SetOperand(Move(Operand));
}
const TSPtr<CExpressionBase>& Operand() const { return _Operand; }
TSPtr<CExpressionBase>&& TakeOperand() { return Move(_Operand); }
void SetOperand(TSPtr<CExpressionBase>&& Operand) { _Operand = Move(Operand); }
virtual const CExpressionBase* FindFirstAsyncSubExpr(const CSemanticProgram& Program) const override { return _Operand.IsValid() ? _Operand->FindFirstAsyncSubExpr(Program) : nullptr; }
virtual void VisitChildren(SAstVisitor& Visitor) const override { Visitor.Visit("Operand", _Operand); }
private:
TSPtr<CExpressionBase> _Operand;
};
class CExprUnaryArithmetic : public CExprInvocation
{
public:
enum class EOp
{
Negate
};
CExprUnaryArithmetic(EOp Op, TSRef<CExpressionBase>&& Rhs)
: CExprInvocation(Move(Rhs))
, _Op(Op)
{
}
TSRef<CExpressionBase> Operand() const { return GetArgument().AsRef(); }
void SetOperand(TSPtr<CExpressionBase>&& NewOperand) { SetArgument(Move(NewOperand)); }
TSPtr<CExpressionBase>&& TakeOperand() { return TakeArgument(); }
EOp Op() const { return _Op; }
private:
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Invoke_UnaryArithmetic; }
virtual bool CanFail(const CAstPackage* Package) const override { return false; }
virtual CUTF8String GetErrorDesc() const override { return "unary negation"; }
virtual bool operator==(const CExpressionBase& Other) const override { return CExprInvocation::operator==(Other); }
EOp _Op;
};
class CExprBinaryArithmetic : public CExprInvocation
{
public:
enum class EOp
{
Add,
Sub,
Mul,
Div
};
CExprBinaryArithmetic(EOp Op, TSRef<CExpressionBase>&& Argument)
: CExprInvocation(Move(Argument))
, _Op(Op)
{
}
EOp Op() const { return _Op; }
private:
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Invoke_BinaryArithmetic; }
virtual CUTF8String GetErrorDesc() const override
{
switch (_Op)
{
case EOp::Add: return "binary addition";
case EOp::Sub: return "binary subtraction";
case EOp::Mul: return "binary multiplication";
case EOp::Div: return "binary division";
default: ULANG_UNREACHABLE();
};
}
virtual bool operator==(const CExpressionBase& Other) const override { return CExprInvocation::operator==(Other) && _Op == static_cast<const CExprBinaryArithmetic&>(Other)._Op; }
virtual void VisitImmediates(SAstVisitor& Visitor) const override
{
CExpressionBase::VisitImmediates(Visitor);
const char* OpString;
switch(_Op)
{
case EOp::Add: OpString = "Add"; break;
case EOp::Sub: OpString = "Sub"; break;
case EOp::Mul: OpString = "Mul"; break;
case EOp::Div: OpString = "Div"; break;
default: ULANG_UNREACHABLE();
};
Visitor.VisitImmediate("Op", OpString);
}
EOp _Op;
};
/**
* Short-circuit evaluation of a Boolean and
**/
class CExprShortCircuitAnd : public CExprBinaryOp
{
public:
CExprShortCircuitAnd(TSPtr<CExpressionBase>&& Lhs, TSPtr<CExpressionBase>&& Rhs) : CExprBinaryOp(Move(Lhs), Move(Rhs)) {}
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Invoke_ShortCircuitAnd; }
virtual const CTypeBase* GetResultType(const CSemanticProgram& Program) const override { return Rhs()->GetResultType(Program); }
virtual bool CanFail(const CAstPackage* Package) const override { return true; }
virtual CUTF8String GetErrorDesc() const override { return "logical '&&'"; }
UE_API virtual bool operator==(const CExpressionBase& Other) const override;
};
/**
* Short-circuit evaluation of a Boolean or
**/
class CExprShortCircuitOr : public CExprBinaryOp
{
public:
CExprShortCircuitOr(TSPtr<CExpressionBase>&& Lhs, TSPtr<CExpressionBase>&& Rhs, const CTypeBase* JoinType = nullptr)
: CExprBinaryOp(Move(Lhs), Move(Rhs))
{
if (JoinType != nullptr)
{
SetResultType(JoinType);
}
}
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Invoke_ShortCircuitOr; }
virtual bool CanFail(const CAstPackage* Package) const override { return Rhs()->CanFail(Package); }
virtual CUTF8String GetErrorDesc() const override { return "logical '||'"; }
UE_API virtual bool operator==(const CExpressionBase& Other) const override;
private:
};
/**
* Logical not operator
*/
class CExprLogicalNot : public CExprUnaryOp
{
public:
CExprLogicalNot(TSPtr<CExpressionBase>&& Operand): CExprUnaryOp(Move(Operand)) {}
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Invoke_LogicalNot; }
UE_API virtual const CTypeBase* GetResultType(const CSemanticProgram& Program) const override;
virtual bool CanFail(const CAstPackage* Package) const override { return true; }
virtual CUTF8String GetErrorDesc() const override { return "logical 'not'"; }
UE_API virtual bool operator==(const CExpressionBase& Other) const override;
};
/**
* Comparison operators.
*/
class CExprComparison : public CExprInvocation
{
public:
using EOp = Verse::Vst::BinaryOpCompare::op;
CExprComparison(EOp Op, TSRef<CExpressionBase>&& Argument)
: CExprInvocation(Move(Argument))
, _Op(Op)
{
_CallsiteBracketStyle = CExprInvocation::EBracketingStyle::SquareBrackets;
}
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Invoke_Comparison; }
UE_API virtual CUTF8String GetErrorDesc() const override;
UE_API virtual bool operator==(const CExpressionBase& Other) const override;
virtual void VisitImmediates(SAstVisitor& Visitor) const override { CExpressionBase::VisitImmediates(Visitor); Visitor.VisitImmediate("Op", Verse::Vst::BinaryCompareOpAsCString(_Op)); }
EOp Op() const { return _Op; }
private:
EOp _Op;
};
/**
* Query the value of a boolean or option value.
**/
class CExprQueryValue : public CExprInvocation
{
public:
CExprQueryValue(TSRef<CExpressionBase>&& Operand)
: CExprInvocation(Move(Operand))
{
_CallsiteBracketStyle = CExprInvocation::EBracketingStyle::SquareBrackets;
}
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Invoke_QueryValue; }
virtual CUTF8String GetErrorDesc() const override { return "postfix '?' operator"; }
};
/**
* Box an option value
*/
class CExprMakeOption : public CExprUnaryOp
{
public:
CExprMakeOption(const CTypeBase* Type, TSPtr<CExpressionBase>&& Operand)
: CExprUnaryOp(Move(Operand))
{
SetResultType(Type);
}
COptionType const* GetOptionType(const CSemanticProgram& Program) const
{
const CTypeBase* MyResultType = GetResultType(Program);
return &(MyResultType->GetNormalType().AsChecked<COptionType>());
}
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Invoke_MakeOption; }
virtual bool CanFail(const CAstPackage* Package) const override { return false; }
virtual CUTF8String GetErrorDesc() const override { return "option value constructor"; }
UE_API virtual bool operator==(const CExpressionBase& Other) const override;
};
/**
* Create an array value
* Can have zero or more subexpressions
*/
class CExprMakeArray : public CExprCompoundBase
{
public:
CExprMakeArray(int32_t ReserveSubExprNum) : CExprCompoundBase(ReserveSubExprNum) {}
const CArrayType* GetArrayType(const CSemanticProgram& Program) const
{
return &GetResultType(Program)->GetNormalType().AsChecked<CArrayType>();
}
//~ Begin CExpressionBase interface
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Invoke_MakeArray; }
virtual CUTF8String GetErrorDesc() const override { return "array value"; }
//~ End CExpressionBase interface
};
/**
* Create a map value
* Can have zero or more subexpressions
*/
class CExprMakeMap : public CExprCompoundBase
{
public:
explicit CExprMakeMap(int32_t ReserveSubExprNum = 0) : CExprCompoundBase(ReserveSubExprNum) {}
const CMapType* GetMapType(const CSemanticProgram& Program) const
{
return &GetResultType(Program)->GetNormalType().AsChecked<CMapType>();
}
//~ Begin CExpressionBase interface
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Invoke_MakeMap; }
virtual CUTF8String GetErrorDesc() const override { return "map value"; }
UE_API virtual bool CanFail(const CAstPackage* Package) const override;
//~ End CExpressionBase interface
};
/**
* Create a tuple value
*/
class CExprMakeTuple : public CExprCompoundBase
{
public:
using CExprCompoundBase::CExprCompoundBase;
const CTupleType* GetTupleType(const CSemanticProgram& Program) const
{
return &GetResultType(Program)->GetNormalType().AsChecked<CTupleType>();
}
//~ Begin CExpressionBase interface
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Invoke_MakeTuple; }
virtual CUTF8String GetErrorDesc() const override { return "tuple value"; }
//~ End CExpressionBase interface
};
/**
* Create a range value
*/
class CExprMakeRange : public CExpressionBase
{
public:
TSRef<CExpressionBase> _Lhs;
TSRef<CExpressionBase> _Rhs;
CExprMakeRange(TSRef<CExpressionBase>&& Lhs, TSRef<CExpressionBase>&& Rhs)
: _Lhs(Move(Lhs))
, _Rhs(Move(Rhs))
{}
void SetLhs(TSRef<CExpressionBase>&& Lhs) { _Lhs = Move(Lhs); }
void SetRhs(TSRef<CExpressionBase>&& Rhs) { _Rhs = Move(Rhs); }
//~ Begin CExpressionBase interface
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Invoke_MakeRange; }
virtual bool CanFail(const CAstPackage* Package) const override { return _Lhs->CanFail(Package) || _Rhs->CanFail(Package); }
virtual CUTF8String GetErrorDesc() const override { return "range constructor"; }
UE_API virtual bool operator==(const CExpressionBase& Other) const override;
//~ End CExpressionBase interface
virtual void VisitChildren(SAstVisitor& Visitor) const override
{
Visitor.Visit("Lhs", _Lhs);
Visitor.Visit("Rhs", _Rhs);
}
};
/**
* Invoke a type as a function on a value - type(expr) or type[expr].
*/
class CExprInvokeType : public CExpressionBase
{
public:
const CTypeBase* _NegativeType;
const bool _bIsFallible;
const TSPtr<CExpressionBase> _TypeAst;
const TSRef<CExpressionBase> _Argument;
UE_API CExprInvokeType(const CTypeBase* NegativeType, const CTypeBase* PositiveType, bool bIsFallible, TSPtr<CExpressionBase>&& TypeAst, TSRef<CExpressionBase>&& Argument);
//~ Begin CExpressionBase interface
UE_API virtual const CExpressionBase* FindFirstAsyncSubExpr(const CSemanticProgram& Program) const override;
virtual bool CanFail(const CAstPackage* Package) const override { return _bIsFallible || _Argument->CanFail(Package); }
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Invoke_Type; }
virtual CUTF8String GetErrorDesc() const override { return "type invocation"; }
UE_API virtual bool operator==(const CExpressionBase& Other) const override;
virtual void VisitChildren(SAstVisitor& Visitor) const override { Visitor.Visit("TypeAst", _TypeAst); Visitor.Visit("Argument", _Argument); }
virtual void VisitImmediates(SAstVisitor& Visitor) const override
{
CExpressionBase::VisitImmediates(Visitor);
Visitor.VisitImmediate("NegativeType", _NegativeType);
Visitor.VisitImmediate("bIsFallible", _bIsFallible);
}
//~ End CExpressionBase interface
};
/**
* Read the value of a variable.
*/
class CExprPointerToReference : public CExprUnaryOp
{
public:
CExprPointerToReference(TSRef<CExpressionBase>&& Variable) : CExprUnaryOp(Move(Variable)) {}
//~ Begin CExpressionBase interface
virtual bool CanFail(const CAstPackage* Package) const override { return Operand()->CanFail(Package); }
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Invoke_PointerToReference; }
virtual CUTF8String GetErrorDesc() const override { return "pointer to reference"; }
UE_API virtual bool operator==(const CExpressionBase& Other) const override;
UE_API virtual const CTypeBase* GetResultType(const CSemanticProgram& Program) const override;
//~ End CExpressionBase interface
};
/**
* Evaluate operand to an l-expression.
*/
class CExprSet : public CExprUnaryOp
{
using CExprUnaryOp::CExprUnaryOp;
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Invoke_Set; }
virtual bool CanFail(const CAstPackage* Package) const override { return Operand()->CanFail(Package); }
virtual CUTF8String GetErrorDesc() const override { return "set"; }
UE_API virtual bool operator==(const CExpressionBase& Other) const override;
};
/**
* Create a new pointer from an initial value.
*/
class CExprNewPointer : public CExpressionBase
{
public:
const TSRef<CExpressionBase> _Value;
CExprNewPointer(const CPointerType* PointerType, TSRef<CExpressionBase>&& Value)
: CExpressionBase(PointerType)
, _Value(Move(Value))
{}
//~ Begin CExpressionBase interface
virtual bool CanFail(const CAstPackage* Package) const override { return _Value->CanFail(Package); }
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Invoke_NewPointer; }
virtual CUTF8String GetErrorDesc() const override { return "pointer new"; }
UE_API virtual bool operator==(const CExpressionBase& Other) const override;
virtual void VisitChildren(SAstVisitor& Visitor) const override { Visitor.Visit("Value", _Value); }
//~ End CExpressionBase interface
};
/**
* Evaluates the value of an expression yielding a reference type.
*/
class CExprReferenceToValue : public CExprUnaryOp
{
public:
UE_API CExprReferenceToValue(TSPtr<CExpressionBase>&& Operand);
//~ Begin CExpressionBase interface
virtual bool CanFail(const CAstPackage* Package) const override { return Operand()->CanFail(Package); }
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Invoke_ReferenceToValue; }
virtual CUTF8String GetErrorDesc() const override { return "convert reference to value"; }
virtual bool operator==(const CExpressionBase& Other) const override { return Other.GetNodeType() == EAstNodeType::Invoke_ReferenceToValue && (*this) == static_cast<const CExprUnaryOp&>(Other); }
//~ End CExpressionBase interface
};
/**
* Code block - `{expr1; expr2}` or `do {expr1; expr2}`
* Can have zero or more subexpressions
**/
class CExprCodeBlock : public CExprCompoundBase
{
public:
// The scope containing locals for this block
TSPtr<CControlScope> _AssociatedScope;
// Methods
explicit CExprCodeBlock(int32_t ReserveSubExprNum = 0) : CExprCompoundBase(ReserveSubExprNum) {}
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Flow_CodeBlock; }
virtual CUTF8String GetErrorDesc() const override { return "code block"; }
UE_API virtual const CTypeBase* GetResultType(const CSemanticProgram& Program) const override;
};
class CExprLet : public CExprCompoundBase
{
using CExprCompoundBase::CExprCompoundBase;
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Flow_Let; }
virtual CUTF8String GetErrorDesc() const override { return "let"; }
UE_API virtual const CTypeBase* GetResultType(const CSemanticProgram& Program) const override;
};
/**
* Return statement - return expr
**/
class CExprReturn : public CExpressionBase
{
public:
CExprReturn() {}
CExprReturn(TSPtr<CExpressionBase>&& Result, const CFunction* Function = nullptr)
{
SetResult(Move(Result));
SetFunction(Function);
}
const TSPtr<CExpressionBase>& Result() const { return _Result; }
void SetResult(TSPtr<CExpressionBase>&& Result) { _Result = Move(Result); }
const CFunction* Function() const { return _Function; }
void SetFunction(const CFunction* Function) { _Function = Function; }
virtual const CExpressionBase* FindFirstAsyncSubExpr(const CSemanticProgram& Program) const override { return _Result.IsValid() ? _Result->FindFirstAsyncSubExpr(Program) : nullptr; }
virtual bool CanFail(const CAstPackage* Package) const override { return _Result.IsValid() && _Result->CanFail(Package); }
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Flow_Return; }
virtual CUTF8String GetErrorDesc() const override { return "return"; }
UE_API virtual const CTypeBase* GetResultType(const CSemanticProgram& Program) const override;
virtual bool MayHaveAttributes() const override { return true; }
virtual void VisitChildren(SAstVisitor& Visitor) const override { Visitor.Visit("Result", _Result); }
virtual bool operator==(const CExpressionBase& Other) const override { return Other.GetNodeType() == EAstNodeType::Flow_Return && IsSubExprEqual(_Result, static_cast<const CExprReturn&>(Other)._Result); }
private:
// Result expression
TSPtr<CExpressionBase> _Result;
// The function being returned from.
const CFunction* _Function{nullptr};
};
/**
* Conditional with failable tests- if (test[]) {clause1}, if (test[]) {clause1} else {else_clause}
**/
class CExprIf : public CExpressionBase
{
public:
CExprIf(TSRef<CExprCodeBlock>&& Condition, TSPtr<CExpressionBase>&& ThenClause, TSPtr<CExpressionBase>&& ElseClause = nullptr)
: _Condition(Move(Condition))
, _ThenClause(Move(ThenClause))
, _ElseClause(Move(ElseClause))
{}
const TSRef<CExprCodeBlock>& GetCondition() const { return _Condition; }
void SetCondition(TSRef<CExprCodeBlock>&& Condition) { _Condition = Move(Condition); }
const TSPtr<CExpressionBase>& GetThenClause() const { return _ThenClause; }
void SetThenClause(TSPtr<CExpressionBase>&& ThenClause) { _ThenClause = Move(ThenClause); }
const TSPtr<CExpressionBase>& GetElseClause() const { return _ElseClause; }
void SetElseClause(TSPtr<CExpressionBase>&& ElseClause) { _ElseClause = Move(ElseClause); }
UE_API virtual const CExpressionBase* FindFirstAsyncSubExpr(const CSemanticProgram& Program) const override;
UE_API virtual bool CanFail(const CAstPackage* Package) const override;
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Flow_If; }
virtual CUTF8String GetErrorDesc() const override { return "if"; }
virtual void VisitChildren(SAstVisitor& Visitor) const override { Visitor.Visit("Condition", _Condition); Visitor.Visit("ThenClause", _ThenClause); Visitor.Visit("ElseClause", _ElseClause); }
virtual void VisitImmediates(SAstVisitor& Visitor) const override { CExpressionBase::VisitImmediates(Visitor); Visitor.VisitImmediate("bIsFilter", _bIsFilter); }
UE_API virtual bool operator==(const CExpressionBase& Other) const override;
// If can be used as a filter in a for(..) { }. Code generation need to know.
bool _bIsFilter{ false };
private:
TSRef<CExprCodeBlock> _Condition;
TSPtr<CExpressionBase> _ThenClause;
TSPtr<CExpressionBase> _ElseClause;
};
/**
* Bounded iteration
**/
class CExprIteration : public CExpressionBase
// Note that CExprSyncIterated, CExprRushIterated and CExprRaceIterated are subclasses
{
public:
CExprIteration() {}
void SetBody(TSPtr<CExpressionBase>&& Body) { _Body = Move(Body); }
void AddFilter(TSRef<CExpressionBase>&& Filter) { _Filters.Add(Move(Filter)); }
UE_API virtual const CExpressionBase* FindFirstAsyncSubExpr(const CSemanticProgram& Program) const override;
virtual bool CanFail(const CAstPackage* Package) const override { return _Body->CanFail(Package); }
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Flow_Iteration; }
virtual CUTF8String GetErrorDesc() const override { return "for"; }
virtual void VisitChildren(SAstVisitor& Visitor) const override { Visitor.VisitArray("Filters", _Filters); Visitor.Visit("Body", _Body); }
UE_API virtual bool operator==(const CExpressionBase& Other) const override;
public:
// The scope containing the variables used for iterating
TSPtr<CControlScope> _AssociatedScope;
// The "filters" that are used
TArray<TSRef<CExpressionBase>> _Filters;
// Expression to evaluate for every iteration that gets past the filters step
TSPtr<CExpressionBase> _Body;
};
/**
* Iteration based concurrency primitives - sync(item:collection){}, rush(item:collection){} or race(item:collection){}
**/
class CExprConcurrentIteratedBase : public CExprIteration
{
public:
virtual const CExpressionBase* FindFirstAsyncSubExpr(const CSemanticProgram& Program) const override { return this; }
};
/**
* Iterated Sync (collection form) concurrency primitive - sync(item:collection) {_coro1() _coro2()}
**/
class CExprSyncIterated : public CExprConcurrentIteratedBase
{
public:
virtual CUTF8String GetErrorDesc() const override { return "sync(:){}"; }
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Concurrent_SyncIterated; }
};
/**
* Iterated Rush (collection form) concurrency primitive - rush(item:collection) {_coro1() _coro2()}
**/
class CExprRushIterated : public CExprConcurrentIteratedBase
{
public:
virtual CUTF8String GetErrorDesc() const override { return "rush(:){}"; }
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Concurrent_RushIterated; }
};
/**
* Iterated Race (collection form) concurrency primitive - race(item:collection) {_coro1() _coro2()}
**/
class CExprRaceIterated : public CExprConcurrentIteratedBase
{
public:
virtual CUTF8String GetErrorDesc() const override { return "race(:){}"; }
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Concurrent_RaceIterated; }
};
/// Base class for all expressions that form a type out of input type(s)
class CExprTypeFormer : public CExpressionBase
{
public:
// Metatype of the actual type formed.
const CTypeType* _TypeType{nullptr};
virtual const CExpressionBase* FindFirstAsyncSubExpr(const CSemanticProgram& Program) const override { return nullptr; }
virtual const CTypeBase* GetResultType(const CSemanticProgram& Program) const override { return _TypeType; }
virtual void VisitImmediates(SAstVisitor& Visitor) const override { CExpressionBase::VisitImmediates(Visitor); Visitor.VisitImmediate("TypeType", _TypeType); }
};
class CExprUnaryTypeFormer : public CExprTypeFormer
{
public:
CExprUnaryTypeFormer(TSRef<CExpressionBase>&& InnerTypeAst): _InnerTypeAst(Move(InnerTypeAst)) {}
const TSRef<CExpressionBase>& GetInnerTypeAst() const { return _InnerTypeAst; }
void SetInnerTypeAst(TSRef<CExpressionBase>&& InnerTypeAst) { _InnerTypeAst = Move(InnerTypeAst); }
// CExpressionBase interface.
virtual const CExpressionBase* FindFirstAsyncSubExpr(const CSemanticProgram& Program) const override { return _InnerTypeAst->FindFirstAsyncSubExpr(Program); }
// CAstNode interface.
virtual void VisitChildren(SAstVisitor& Visitor) const override { Visitor.Visit("InnerTypeAst", _InnerTypeAst); }
private:
TSRef<CExpressionBase> _InnerTypeAst;
};
class CExprArrayTypeFormer : public CExprUnaryTypeFormer
{
public:
CExprArrayTypeFormer(TSRef<CExpressionBase>&& InnerTypeAst): CExprUnaryTypeFormer(Move(InnerTypeAst)) {}
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Invoke_ArrayFormer; }
virtual CUTF8String GetErrorDesc() const override { return "array type"; }
bool operator==(const CExpressionBase& Other) const override { return false; }
const CArrayType* GetArrayType() const
{
ULANG_ASSERTF(_TypeType, "GetArrayType called on unanalyzed expression");
return &_TypeType->PositiveType()->GetNormalType().AsChecked<CArrayType>();
}
};
class CExprGeneratorTypeFormer : public CExprUnaryTypeFormer
{
public:
/// Construct an expression that takes the `ValueType` and forms an Generator of `ValueType`.
CExprGeneratorTypeFormer(TSRef<CExpressionBase>&& InnerTypeAst) : CExprUnaryTypeFormer(Move(InnerTypeAst)) {}
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Invoke_GeneratorFormer; }
virtual CUTF8String GetErrorDesc() const override { return "generator(..)"; }
virtual bool operator==(const CExpressionBase& Other) const override { return false; }
const CGeneratorType* GetGeneratorType() const
{
ULANG_ASSERTF(_TypeType, "GetGeneratorType called on unanalyzed expression");
return &_TypeType->PositiveType()->GetNormalType().AsChecked<CGeneratorType>();
}
};
class CExprMapTypeFormer : public CExprTypeFormer
{
public:
CExprMapTypeFormer(TArray<TSRef<CExpressionBase>>&& KeyTypeAsts, TSRef<CExpressionBase>&& ValueTypeAst)
: CExprTypeFormer()
, _KeyTypeAsts(KeyTypeAsts)
, _ValueTypeAst(ValueTypeAst)
{}
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Invoke_MapFormer; }
virtual CUTF8String GetErrorDesc() const override { return "map type"; }
bool operator==(const CExpressionBase& Other) const override { return false; }
const TArray<TSRef<CExpressionBase>>& KeyTypeAsts() const { return _KeyTypeAsts; }
void SetKeyTypeAst(TSRef<CExpressionBase>&& KeyTypeAst, int32_t Index) { _KeyTypeAsts[Index] = Move(KeyTypeAst); }
const TSRef<CExpressionBase>& ValueTypeAst() const { return _ValueTypeAst; }
void SetValueTypeAst(TSRef<CExpressionBase>&& ValueTypeAst) { _ValueTypeAst = Move(ValueTypeAst); }
const CMapType* GetMapType() const
{
ULANG_ASSERTF(_TypeType, "GetMapType called on unanalyzed expression");
return &_TypeType->PositiveType()->GetNormalType().AsChecked<CMapType>();
}
// CExpressionBase interface.
UE_API virtual const CExpressionBase* FindFirstAsyncSubExpr(const CSemanticProgram& Program) const override;
// CAstNode interface.
virtual void VisitChildren(SAstVisitor& Visitor) const override { Visitor.VisitArray("KeyTypeAsts", _KeyTypeAsts); Visitor.Visit("ValueTypeAst", _ValueTypeAst); }
private:
TArray<TSRef<CExpressionBase>> _KeyTypeAsts;
TSRef<CExpressionBase> _ValueTypeAst;
};
class CExprOptionTypeFormer : public CExprUnaryTypeFormer
{
public:
CExprOptionTypeFormer(TSRef<CExpressionBase>&& InnerTypeAst): CExprUnaryTypeFormer(Move(InnerTypeAst)) {}
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Invoke_OptionFormer; }
virtual CUTF8String GetErrorDesc() const override { return "option type"; }
virtual bool operator==(const CExpressionBase& Other) const override { return false; }
const COptionType* GetOptionType() const
{
ULANG_ASSERTF(_TypeType, "GetOptionType called on unanalyzed expression");
return &_TypeType->NegativeType()->GetNormalType().AsChecked<COptionType>();
}
};
class CExprSubtype : public CExprUnaryTypeFormer
{
public:
/// Construct an expression that takes the `ValueType` and forms an option of `ValueType`.
CExprSubtype(TSRef<CExpressionBase>&& InnerTypeAst): CExprUnaryTypeFormer(Move(InnerTypeAst)) {}
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Invoke_Subtype; }
virtual CUTF8String GetErrorDesc() const override { return _bCastableSubtype ? "castable_subtype(..)" : "subtype(..)"; }
virtual bool operator==(const CExpressionBase& Other) const override { return false; }
UE_API const CTypeType& GetSubtypeType() const;
bool _bCastableSubtype = false;
};
// Get or create a tuple based on `tuple(type1, type2, ...)`
class CExprTupleType : public CExprTypeFormer
{
public:
CExprTupleType(int32_t ReserveTypeExprNum = 0) { _ElementTypeExprs.Reserve(ReserveTypeExprNum); }
const TSPtrArray<CExpressionBase>& GetElementTypeExprs() const { return _ElementTypeExprs; }
TSPtrArray<CExpressionBase>& GetElementTypeExprs() { return _ElementTypeExprs; }
void ReplaceElementTypeExpr(TSPtr<CExpressionBase>&& TypeExpr, int32_t Index)
{
ULANG_ASSERTF(Index >= 0 && Index < _ElementTypeExprs.Num(), "Replacing invalid subexpression index");
_ElementTypeExprs.ReplaceAt(Move(TypeExpr), Index);
}
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Invoke_TupleType; }
virtual CUTF8String GetErrorDesc() const override { return "tuple(..)"; }
virtual void VisitChildren(SAstVisitor& Visitor) const override { Visitor.VisitArray("ElemTypeExprs", _ElementTypeExprs); }
UE_API virtual bool operator==(const CExpressionBase& Other) const override;
const CTupleType* GetTupleType() const
{
ULANG_ASSERTF(_TypeType, "GetTupleType called on unanalyzed expression");
return &_TypeType->PositiveType()->GetNormalType().AsChecked<CTupleType>();
}
protected:
TSPtrArray<CExpressionBase> _ElementTypeExprs;
};
/**
* Create a function type from a parameter and return type.
* Also used on the LHS of a definition as a pattern for iteration pairs.
*/
class CExprArrow : public CExprTypeFormer
{
public:
CExprArrow(TSRef<CExpressionBase>&& Domain, TSRef<CExpressionBase>&& Range)
: _Domain(Move(Domain))
, _Range(Move(Range))
{}
const TSRef<CExpressionBase>& Domain() const { return _Domain; }
const TSRef<CExpressionBase>& Range() const { return _Range; }
void SetDomain(TSRef<CExpressionBase>&& NewDomain) { _Domain = Move(NewDomain); }
void SetRange(TSRef<CExpressionBase>&& NewRange) { _Range = Move(NewRange); }
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Invoke_Arrow; }
virtual CUTF8String GetErrorDesc() const override { return "function type"; }
virtual bool operator==(const CExpressionBase& Other) const override
{
return GetNodeType() == Other.GetNodeType()
&& IsSubExprEqual(_Domain, static_cast<const CExprArrow&>(Other)._Domain)
&& IsSubExprEqual(_Range, static_cast<const CExprArrow&>(Other)._Range);
}
virtual void VisitChildren(SAstVisitor& Visitor) const override { Visitor.Visit("Domain", _Domain); Visitor.Visit("Range", _Range); }
const CFunctionType* GetFunctionType() const
{
ULANG_ASSERTF(_TypeType, "GetFunctionType called on unanalyzed expression");
return &_TypeType->PositiveType()->GetNormalType().AsChecked<CFunctionType>();
}
private:
TSRef<CExpressionBase> _Domain;
TSRef<CExpressionBase> _Range;
};
/**
* Represents an initializer-list style construction for certain object types;
* i.e.: Type{expr1, id=expr2, ...}
*/
class CExprArchetypeInstantiation : public CExpressionBase
{
public:
UE_API CExprArchetypeInstantiation(TSRef<CExpressionBase>&& ClassAst, CExprMacroCall::CClause&& BodyAst, const CTypeBase* ResultType);
UE_API const CClass* GetClass(const CSemanticProgram& Program) const;
const TSRefArray<CExpressionBase>& Arguments() const { return _Arguments; }
int32_t AppendArgument(TSRef<CExpressionBase>&& Argument)
{
return _Arguments.Add(Move(Argument));
}
virtual bool CanFail(const CAstPackage* Package) const override
{
for (const auto& Argument : _Arguments)
{
if (Argument->CanFail(Package))
{
return true;
}
}
return false;
}
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Invoke_ArchetypeInstantiation; }
virtual CUTF8String GetErrorDesc() const override { return "archetype constructor"; }
virtual void VisitChildren(SAstVisitor& Visitor) const override
{
Visitor.Visit("ClassAst", _ClassAst);
Visitor.VisitArray("BodyAstExprs", _BodyAst.Exprs());
Visitor.BeginArray("Arguments", _Arguments.Num());
for(const TSRef<CExpressionBase>& Argument : _Arguments)
{
Visitor.VisitElement(Argument);
}
Visitor.EndArray();
}
virtual void VisitImmediates(SAstVisitor& Visitor) const override
{
CExpressionBase::VisitImmediates(Visitor);
Visitor.VisitImmediate("BodyAstTag", MacroClauseTagAsCString(_BodyAst.Tag()));
Visitor.VisitImmediate("BodyAstForm", MacroClauseFormAsCString(_BodyAst.Form()));
}
UE_API bool operator==(const CExpressionBase& Other) const override;
TSRef<CExpressionBase> _ClassAst;
CExprMacroCall::CClause _BodyAst;
private:
TSRefArray<CExpressionBase> _Arguments;
};
/**
* Block based concurrency primitives - sync{}, rush{} or race{}
* Can have two or more async subexpressions - 0 or 1 is a warning or error.
**/
class CExprConcurrentBlockBase : public CExprCompoundBase
{
public:
explicit CExprConcurrentBlockBase(int32_t ReserveSubExprNum = 0) : CExprCompoundBase(ReserveSubExprNum) {}
virtual const CExpressionBase* FindFirstAsyncSubExpr(const CSemanticProgram& Program) const override { return this; }
};
/**
* Sync concurrency primitive - sync {_coro1() _coro2()}
* 2+ Async expressions run concurrently and next expression executed when *all* expressions
* completed. Its overall result is the result of the last expression in the block to complete
* (using most specific common compatible result type of all expressions or no result if there is
* no common type). Expressions may only be async (such as coroutines).
**/
class CExprSync : public CExprConcurrentBlockBase
{
public:
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Concurrent_Sync; }
virtual CUTF8String GetErrorDesc() const override { return "sync{}"; }
};
/**
* Race concurrency primitive - race {_coro1() _coro2()}
* 2+ Async expressions run concurrently and next expression executed when *fastest/first*
* expression completed and all other expressions are aborted. Its overall result is result of
* first expression in block to complete (using most specific common compatible result type of all
* expressions or no result if there is no common type).
**/
class CExprRace : public CExprConcurrentBlockBase
{
public:
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Concurrent_Race; }
virtual CUTF8String GetErrorDesc() const override { return "race{}"; }
};
/**
* Rush concurrency primitive - rush {_coro1() _coro2()}
* 2+ Async expressions run concurrently and next expression executed when *fastest/first*
* expression completed and all other expressions continue independently until each is fully
* completed. Its overall result is the result of the first expression in the block to complete
* (using most specific common compatible result type of all expressions or no result if there is
* no common type).
**/
class CExprRush : public CExprConcurrentBlockBase
{
public:
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Concurrent_Rush; }
virtual CUTF8String GetErrorDesc() const override { return "rush{}"; }
};
/**
* Expressions with a sub-block - branch, spawn, loop, defer
**/
class CExprSubBlockBase : public CExpressionBase
{
protected:
// Sub-expression from block - either single expression or block of expressions
TSPtr<CExpressionBase> _BlockExpr;
public:
void SetExpr(TSPtr<CExpressionBase>&& Expr) { _BlockExpr = Move(Expr); }
const TSPtr<CExpressionBase>& Expr() const { return _BlockExpr; }
virtual const CExpressionBase* FindFirstAsyncSubExpr(const CSemanticProgram& Program) const override { return nullptr; }
virtual void VisitChildren(SAstVisitor& Visitor) const override { Visitor.Visit("BlockExpr", _BlockExpr); }
virtual bool operator==(const CExpressionBase& Other) const override { return (Other.GetNodeType() == GetNodeType()) && IsSubExprEqual(_BlockExpr, static_cast<const CExprSubBlockBase&>(Other)._BlockExpr); }
};
/**
* Branch concurrency primitive - branch {Coro()}
* One async expression started and next expression executed immediately while the started
* expression continues independently until completion or the surrounding context (such as a
* coroutine) completes in which case it aborts early. Result is a handle to the invoked coroutine / invoked
* expression (also known as a future or promise) tracking the expression.
**/
class CExprBranch : public CExprSubBlockBase
{
public:
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Concurrent_Branch; }
virtual CUTF8String GetErrorDesc() const override { return "branch"; }
};
/**
* Spawn concurrency primitive - spawn {Coro()} [future: spawn {Expr1; Expr2}]
* Async expression treated as a closure/lambda with next expression executed
* immediately while the started async expression continues independently. Has no result.
* spawn essentially makes any async expression an immediate expression. This also means that
* it can allow async expressions / coroutines to be called within immediate functions.
**/
class CExprSpawn : public CExprSubBlockBase
{
public:
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Concurrent_Spawn; }
virtual CUTF8String GetErrorDesc() const override { return "spawn"; }
};
/**
* Loop flow/concurrency primitive/macro - loop {Expr1; Expr2}
* Loops one or more expressions.
* For safety/security it *must* have at least one async expression, `break`, or `return`
* so it is less likely to have an infinite loop within a single update.
**/
class CExprLoop : public CExprSubBlockBase
{
public:
virtual const CExpressionBase* FindFirstAsyncSubExpr(const CSemanticProgram& Program) const override { return _BlockExpr->FindFirstAsyncSubExpr(Program); }
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Flow_Loop; }
virtual CUTF8String GetErrorDesc() const override { return "loop"; }
virtual bool CanFail(const CAstPackage* Package) const override {
return _BlockExpr->CanFail(Package);
}
};
/**
* defer macro - defer {Expr1; Expr2}
* Defers expressions until end of current scope. Only called if encountered in flow and called in reverse order encountered.
**/
class CExprDefer : public CExprSubBlockBase
{
public:
virtual const CExpressionBase* FindFirstAsyncSubExpr(const CSemanticProgram& Program) const override { return _BlockExpr->FindFirstAsyncSubExpr(Program); }
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Flow_Defer; }
virtual CUTF8String GetErrorDesc() const override { return "defer"; }
};
/**
* Control flow early exit
*
* loop:
* if (IsEarlyExit[]):
* break
* DoLoopStuff()
**/
class CExprBreak : public CExpressionBase
{
public:
const CExpressionBase* _AssociatedControlFlow{nullptr};
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Flow_Break; }
virtual CUTF8String GetErrorDesc() const override { return "break"; }
virtual bool operator==(const CExpressionBase& Other) const override { return Other.GetNodeType() == EAstNodeType::Flow_Break; }
virtual bool MayHaveAttributes() const override { return true; }
UE_API virtual const CTypeBase* GetResultType(const CSemanticProgram& Program) const override;
};
/**
* Represents members of a class/interface/module/snippet definition node
*/
class CMemberDefinitions
{
public:
CMemberDefinitions() {}
CMemberDefinitions(TArray<TSRef<CExpressionBase>>&& Members) : _Members(Move(Members)) {}
const TArray<TSRef<CExpressionBase>>& Members() const { return _Members; }
void SetMembers(TArray<TSRef<CExpressionBase>>&& Members) { _Members = Move(Members); }
void AppendMember(TSRef<CExpressionBase>&& Member) { _Members.Add(Move(Member)); }
void SetMember(TSRef<CExpressionBase>&& Member, int32_t Index) { _Members[Index] = Move(Member); }
void VisitMembers(SAstVisitor& Visitor) const { Visitor.VisitArray("Members", _Members); }
private:
TArray<TSRef<CExpressionBase>> _Members;
};
/**
* Represents a snippet in the AST.
*/
class CExprSnippet : public CExpressionBase, public CMemberDefinitions
{
public:
CUTF8String _Path;
CSnippet* _SemanticSnippet{ nullptr };
CExprSnippet(const CUTF8StringView& Path) : _Path(Path) {}
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Context_Snippet; }
virtual CUTF8String GetErrorDesc() const override { return "snippet"; }
virtual bool operator==(const CExpressionBase& Other) const override { return Other.GetNodeType() == EAstNodeType::Context_Snippet && static_cast<const CExprSnippet&>(Other)._SemanticSnippet == _SemanticSnippet; }
UE_API virtual const CTypeBase* GetResultType(const CSemanticProgram& Program) const override;
virtual void VisitChildren(SAstVisitor& Visitor) const override { VisitMembers(Visitor); }
virtual void VisitImmediates(SAstVisitor& Visitor) const override { CExpressionBase::VisitImmediates(Visitor); Visitor.VisitImmediate("Path", _Path); }
};
/**
* Represents a module definition in the AST.
*/
class CExprModuleDefinition : public CExpressionBase, public CMemberDefinitions
{
public:
CUTF8String _Name;
CModulePart* _SemanticModule{ nullptr }; // You can get the CModule from this as well
bool _bLegacyPublic = false; // To emulate legacy behavior while vmodule files are allowed
CExprModuleDefinition(const CUTF8StringView& Name, EVstMappingType VstMappingType = EVstMappingType::Ast)
: CExpressionBase(VstMappingType)
, _Name(Name)
{}
UE_API CExprModuleDefinition(CModulePart& Module, TArray<TSRef<CExpressionBase>>&& Members);
UE_API ~CExprModuleDefinition();
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Definition_Module; }
virtual CUTF8String GetErrorDesc() const override { return "module definition"; }
virtual bool operator==(const CExpressionBase& Other) const override { return Other.GetNodeType() == EAstNodeType::Definition_Module && static_cast<const CExprModuleDefinition&>(Other)._SemanticModule == _SemanticModule; }
UE_API virtual const CTypeBase* GetResultType(const CSemanticProgram& Program) const override;
virtual void VisitChildren(SAstVisitor& Visitor) const override { VisitMembers(Visitor); }
virtual void VisitImmediates(SAstVisitor& Visitor) const override { CExpressionBase::VisitImmediates(Visitor); Visitor.VisitImmediate("Name", _Name); }
virtual bool CanBePathSegment(const TMacroSymbols& MacroSymbols) const override { return true; }
};
/**
* Represents an enum definition in the AST.
*/
class CExprEnumDefinition : public CExpressionBase
{
public:
CEnumeration& _Enum;
const TArray<TSRef<CExpressionBase>> _Members;
UE_API CExprEnumDefinition(CEnumeration& Enum, TArray<TSRef<CExpressionBase>>&& Members, EVstMappingType = EVstMappingType::Ast);
UE_API ~CExprEnumDefinition();
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Definition_Enum; }
virtual CUTF8String GetErrorDesc() const override { return "enum definition"; }
virtual bool operator==(const CExpressionBase& Other) const override { return Other.GetNodeType() == EAstNodeType::Definition_Enum && &static_cast<const CExprEnumDefinition&>(Other)._Enum == &_Enum; }
UE_API virtual const CTypeBase* GetResultType(const CSemanticProgram& Program) const override;
virtual void VisitChildren(SAstVisitor& Visitor) const override { Visitor.VisitArray("Members", _Members); }
UE_API virtual void VisitImmediates(SAstVisitor& Visitor) const override;
virtual bool CanBePathSegment(const TMacroSymbols& MacroSymbols) const override { return true; }
};
/**
* Represents both named and anonymous scoped access level definitions in the AST.
* e.g. foo_scope := scoped{A,B,C} #named
* foo<scoped{A,B,C}> := 42 # anonymous
*/
class CExprScopedAccessLevelDefinition : public CExpressionBase
{
public:
TSRef<CScopedAccessLevelDefinition> _AccessLevelDefinition;
TArray<TSRef<CExpressionBase>> _ScopeReferenceExprs;
UE_API CExprScopedAccessLevelDefinition(TSRef<CScopedAccessLevelDefinition>& AccessLevelDefinition, EVstMappingType VstMappingType = EVstMappingType::Ast);
UE_API ~CExprScopedAccessLevelDefinition();
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Definition_ScopedAccessLevel; }
virtual CUTF8String GetErrorDesc() const override { return "scoped access level"; }
virtual bool operator==(const CExpressionBase& Other) const override { return Other.GetNodeType() == EAstNodeType::Definition_ScopedAccessLevel && static_cast<const CExprScopedAccessLevelDefinition&>(Other)._AccessLevelDefinition == _AccessLevelDefinition; }
virtual void VisitChildren(SAstVisitor& Visitor) const override { Visitor.VisitArray("Scopes", _ScopeReferenceExprs); }
UE_API virtual void VisitImmediates(SAstVisitor& Visitor) const override;
};
/**
* Represents a interface definition in the AST.
*/
class CExprInterfaceDefinition : public CExpressionBase, public CMemberDefinitions
{
public:
CInterface& _Interface;
const TArray<TSRef<CExpressionBase>>& SuperInterfaces() const { return _SuperInterfaces; }
void SetSuperInterfaces(TArray<TSRef<CExpressionBase>>&& SuperInterfaces) { _SuperInterfaces = SuperInterfaces; }
void SetSuperInterface(TSRef<CExpressionBase>&& SuperInterface, int32_t Index) { _SuperInterfaces[Index] = Move(SuperInterface); }
UE_API CExprInterfaceDefinition(CInterface& Interface, TArray<TSRef<CExpressionBase>>&& SuperInterfaces, TArray<TSRef<CExpressionBase>>&& Members, EVstMappingType = EVstMappingType::Ast);
CExprInterfaceDefinition(CInterface& Interface, EVstMappingType VstMappingType = EVstMappingType::Ast)
: CExprInterfaceDefinition(Interface, {}, {}, VstMappingType)
{}
UE_API ~CExprInterfaceDefinition();
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Definition_Interface; }
virtual CUTF8String GetErrorDesc() const override { return "interface definition"; }
virtual bool operator==(const CExpressionBase& Other) const override { return Other.GetNodeType() == EAstNodeType::Definition_Interface && &static_cast<const CExprInterfaceDefinition&>(Other)._Interface == &_Interface; }
virtual void VisitChildren(SAstVisitor& Visitor) const override { VisitMembers(Visitor); }
UE_API virtual void VisitImmediates(SAstVisitor& Visitor) const override;
virtual bool MayHaveAttributes() const override { return true; }
virtual bool CanBePathSegment(const TMacroSymbols& MacroSymbols) const override { return true; }
private:
TArray<TSRef<CExpressionBase>> _SuperInterfaces;
};
/**
* Represents a class definition in the AST.
*/
class CExprClassDefinition : public CExpressionBase, public CMemberDefinitions
{
public:
CClass& _Class;
UE_API CExprClassDefinition(CClass& Class, TArray<TSRef<CExpressionBase>>&& SuperTypes, TArray<TSRef<CExpressionBase>>&& Members, EVstMappingType = EVstMappingType::Ast);
CExprClassDefinition(CClass& Class, EVstMappingType VstMappingType = EVstMappingType::Ast)
: CExprClassDefinition(Class, {}, {}, VstMappingType)
{
}
UE_API ~CExprClassDefinition();
const TArray<TSRef<CExpressionBase>>& SuperTypes() const { return _SuperTypes; }
void SetSuperTypes(TArray<TSRef<CExpressionBase>>&& SuperTypes) { _SuperTypes = Move(SuperTypes); }
void SetSuperType(TSRef<CExpressionBase>&& SuperType, int32_t Index) { _SuperTypes[Index] = Move(SuperType); }
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Definition_Class; }
virtual CUTF8String GetErrorDesc() const override { return "class definition"; }
virtual bool operator==(const CExpressionBase& Other) const override { return Other.GetNodeType() == EAstNodeType::Definition_Class && &static_cast<const CExprClassDefinition&>(Other)._Class == &_Class; }
virtual void VisitChildren(SAstVisitor& Visitor) const override { VisitMembers(Visitor); }
UE_API virtual void VisitImmediates(SAstVisitor& Visitor) const override;
virtual bool CanBePathSegment(const TMacroSymbols& MacroSymbols) const override { return true; }
private:
TArray<TSRef<CExpressionBase>> _SuperTypes;
};
/**
* Represents a data definition in the AST.
*/
class CExprDataDefinition : public CExprDefinition
{
public:
const TSRef<CDataDefinition> _DataMember;
UE_API CExprDataDefinition(const TSRef<CDataDefinition>& DataMember, TSPtr<CExpressionBase>&& Element, TSPtr<CExpressionBase>&& ValueDomain, TSPtr<CExpressionBase>&& Value, EVstMappingType = EVstMappingType::Ast);
UE_API ~CExprDataDefinition();
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Definition_Data; }
virtual CUTF8String GetErrorDesc() const override { return "data definition"; }
virtual bool operator==(const CExpressionBase& Other) const override { return Other.GetNodeType() == EAstNodeType::Definition_Data && &static_cast<const CExprDataDefinition&>(Other)._DataMember == &_DataMember; }
UE_API virtual const CTypeBase* GetResultType(const CSemanticProgram& Program) const override;
virtual void VisitImmediates(SAstVisitor& Visitor) const override { CExpressionBase::VisitImmediates(Visitor); Visitor.VisitImmediate("DataMember", *_DataMember); }
};
/**
* Represents a map pair definition in the AST: (Key=>Value):Map
*/
class CExprIterationPairDefinition : public CExprDefinition
{
public:
const TSRef<CDataDefinition> _KeyDefinition;
const TSRef<CDataDefinition> _ValueDefinition;
UE_API CExprIterationPairDefinition(
TSRef<CDataDefinition>&& KeyDefinition,
TSRef<CDataDefinition>&& ValueDefinition,
TSPtr<CExpressionBase>&& Element,
TSPtr<CExpressionBase>&& ValueDomain,
TSPtr<CExpressionBase>&& Value,
EVstMappingType VstMappingType = EVstMappingType::Ast);
UE_API ~CExprIterationPairDefinition();
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Definition_IterationPair; }
virtual CUTF8String GetErrorDesc() const override { return "iteration pair definition"; }
virtual bool operator==(const CExpressionBase& Other) const override { return Other.GetNodeType() == EAstNodeType::Definition_IterationPair && static_cast<const CExprIterationPairDefinition&>(Other)._KeyDefinition == _KeyDefinition && static_cast<const CExprIterationPairDefinition&>(Other)._ValueDefinition == _ValueDefinition; }
virtual void VisitImmediates(SAstVisitor& Visitor) const override { CExpressionBase::VisitImmediates(Visitor); Visitor.VisitImmediate("KeyDefinition", *_KeyDefinition); Visitor.VisitImmediate("ValueDefinition", *_ValueDefinition); }
};
/**
* Add an item to an array
* The array itself is not included in the node,
* instead the result destination in the code generator is used.
* In the future this will be explicit in the IR, but for now it's inside code generation.
**/
class CIrArrayAdd : public CExpressionBase
{
public:
CIrArrayAdd(TSRef<CExpressionBase>&& Source)
: CExpressionBase(EVstMappingType::Ir)
, _Source(Move(Source))
{}
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Ir_ArrayAdd; }
virtual CUTF8String GetErrorDesc() const override { return "array add"; }
UE_API virtual bool operator==(const CExpressionBase& Other) const override;
virtual const CExpressionBase* FindFirstAsyncSubExpr(const CSemanticProgram& Program) const override {return _Source->FindFirstAsyncSubExpr(Program); }
virtual bool CanFail(const CAstPackage* Package) const override { return _Source->CanFail(Package); }
virtual void VisitChildren(SAstVisitor& Visitor) const override { Visitor.Visit("Source", _Source); }
TSRef<CExpressionBase> _Source;
};
/// @see CIrArrayAdd
class CIrMapAdd : public CExpressionBase
{
public:
CIrMapAdd(TSRef<CExpressionBase>&& Key, TSRef<CExpressionBase>&& Value)
: CExpressionBase(EVstMappingType::Ir)
, _Key(Move(Key))
, _Value(Move(Value))
{
}
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Ir_MapAdd; }
virtual CUTF8String GetErrorDesc() const override { return "map add"; }
UE_API virtual bool operator==(const CExpressionBase&) const override;
UE_API virtual const CExpressionBase* FindFirstAsyncSubExpr(const CSemanticProgram&) const override;
UE_API virtual bool CanFail(const CAstPackage* Package) const override;
UE_API virtual void VisitChildren(SAstVisitor& Visitor) const override;
TSRef<CExpressionBase> _Key;
TSRef<CExpressionBase> _Value;
};
class CIrArrayUnsafeCall : public CExpressionBase
{
public:
CIrArrayUnsafeCall(TSRef<CExpressionBase>&& Callee, TSRef<CExpressionBase>&& Arguments)
: _Callee(Move(Callee))
, _Argument(Move(Arguments))
{
}
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Ir_ArrayUnsafeCall; }
virtual CUTF8String GetErrorDesc() const override { return "array unsafe call"; }
UE_API virtual bool operator==(const CExpressionBase&) const override;
virtual const CExpressionBase* FindFirstAsyncSubExpr(const CSemanticProgram& Program) const override
{
return _Callee->FindFirstAsyncSubExpr(Program);
}
virtual bool CanFail(const CAstPackage* Package) const override
{
return
_Callee->CanFail(Package) ||
_Argument->CanFail(Package);
}
virtual void VisitChildren(SAstVisitor& Visitor) const override
{
Visitor.Visit("Callee", _Callee);
Visitor.Visit("Argument", _Argument);
}
TSRef<CExpressionBase> _Callee;
TSRef<CExpressionBase> _Argument;
};
/**
* Converts a value to a dynamically typed value. Only present in the IR, not the AST.
*/
class CIrConvertToDynamic : public CExprUnaryOp
{
public:
UE_API CIrConvertToDynamic(const CTypeBase* ResultType, TSRef<CExpressionBase>&& Value);
//~ Begin CExpressionBase interface
virtual bool CanFail(const CAstPackage* Package) const override { return Operand()->CanFail(Package); }
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Ir_ConvertToDynamic; }
virtual CUTF8String GetErrorDesc() const override { return "convert value to dynamically typed value"; }
virtual bool operator==(const CExpressionBase& Other) const override { return Other.GetNodeType() == EAstNodeType::Ir_ConvertToDynamic && (*this) == static_cast<const CExprUnaryOp&>(Other); }
//~ End CExpressionBase interface
};
/**
* Converts a value to a dynamically typed value. Only present in the IR, not the AST.
*/
class CIrConvertFromDynamic : public CExprUnaryOp
{
public:
UE_API CIrConvertFromDynamic(const CTypeBase* ResultType, TSRef<CExpressionBase>&& Value);
//~ Begin CExpressionBase interface
virtual bool CanFail(const CAstPackage* Package) const override { return Operand()->CanFail(Package); }
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Ir_ConvertFromDynamic; }
virtual CUTF8String GetErrorDesc() const override { return "convert value from dynamically typed value"; }
virtual bool operator==(const CExpressionBase& Other) const override { return Other.GetNodeType() == EAstNodeType::Ir_ConvertFromDynamic && (*this) == static_cast<const CExprUnaryOp&>(Other); }
//~ End CExpressionBase interface
};
/**
* Bounded iteration
**/
class CIrFor : public CExpressionBase
{
public:
bool _bOutermost{ true };
bool _bGenerateResult{ true };
bool _bCanFail{ false };
const TSPtr<CDataDefinition> _KeyMember;
const TSRef<CDataDefinition> _DataMember;
const TSRef<CExprDefinition> _Definition;
CIrFor(const TSRef<CDataDefinition>& DataMember, TSPtr<CExpressionBase>&& Element, TSPtr<CExpressionBase>&& ValueDomain, TSPtr<CExpressionBase>&& Value)
: CExpressionBase(EVstMappingType::Ir)
, _KeyMember()
, _DataMember(DataMember)
, _Definition(TSRef<CExprDefinition>::New(Move(Element), Move(ValueDomain), Move(Value), EVstMappingType::Ir)) {}
CIrFor(const TSRef<CDataDefinition>& KeyMember, const TSRef<CDataDefinition>& DataMember, TSPtr<CExpressionBase>&& Element, TSPtr<CExpressionBase>&& ValueDomain, TSPtr<CExpressionBase>&& Value)
: CExpressionBase(EVstMappingType::Ir)
, _KeyMember(KeyMember)
, _DataMember(DataMember)
, _Definition(TSRef<CExprDefinition>::New(Move(Element), Move(ValueDomain), Move(Value), EVstMappingType::Ir)) {}
void SetBody(TSPtr<CExpressionBase>&& Body) { _Body = Move(Body); }
UE_API virtual const CExpressionBase* FindFirstAsyncSubExpr(const CSemanticProgram& Program) const override;
virtual bool CanFail(const CAstPackage* Package) const override { return _bCanFail; }
virtual void VisitChildren(SAstVisitor& Visitor) const override { Visitor.Visit("Definition", _Definition); Visitor.Visit("Body", _Body); }
virtual void VisitImmediates(SAstVisitor& Visitor) const override
{
CExpressionBase::VisitImmediates(Visitor);
Visitor.VisitImmediate("bGenerateResult", _bGenerateResult);
if (_KeyMember)
{
Visitor.VisitImmediate("KeyMember", *_KeyMember);
}
Visitor.VisitImmediate("DataMember", *_DataMember);
}
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Ir_For; }
virtual CUTF8String GetErrorDesc() const override { return "ir_for"; }
UE_API virtual bool operator==(const CExpressionBase& Other) const override;
public:
// The scope containing the variables used for iterating
TSPtr<CControlScope> _AssociatedScope;
// Expression to evaluate for every iteration that gets past the filters step
TSPtr<CExpressionBase> _Body;
};
/**
* Wraps the innermost body of CIrFor
* It wraps the code not inside the failure context of CIrFor.
**/
class CIrForBody : public CExpressionBase
{
public:
CIrForBody(TSPtr<CExpressionBase>&& Body)
: CExpressionBase(EVstMappingType::Ir)
, _Body(Body) {}
void SetBody(TSPtr<CExpressionBase>&& Body) { _Body = Move(Body); }
UE_API virtual const CExpressionBase* FindFirstAsyncSubExpr(const CSemanticProgram& Program) const override;
virtual bool CanFail(const CAstPackage* Package) const override { return _Body->CanFail(Package); }
virtual void VisitChildren(SAstVisitor& Visitor) const override { Visitor.Visit("Body", _Body); }
virtual void VisitImmediates(SAstVisitor& Visitor) const override {}
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Ir_ForBody; }
virtual CUTF8String GetErrorDesc() const override { return "ir_for_body"; }
UE_API virtual bool operator==(const CExpressionBase& Other) const override;
public:
// Expression to evaluate outside the failure contexts of the enclosing CIrFor
TSPtr<CExpressionBase> _Body;
};
/**
* Represents a function definition in the AST.
*/
class CExprFunctionDefinition : public CExprDefinition
{
public:
const TSRef<CFunction> _Function;
UE_API CExprFunctionDefinition(const TSRef<CFunction>& Function, TSPtr<CExpressionBase>&& Element, TSPtr<CExpressionBase>&& ValueDomain, TSPtr<CExpressionBase>&& Value, EVstMappingType = EVstMappingType::Ast);
UE_API ~CExprFunctionDefinition();
UE_API bool HasUserAddedPredictsEffect(const CSemanticProgram& Program) const;
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Definition_Function; }
virtual CUTF8String GetErrorDesc() const override { return "function definition"; }
virtual bool operator==(const CExpressionBase& Other) const override { return Other.GetNodeType() == EAstNodeType::Definition_Function && static_cast<const CExprFunctionDefinition&>(Other)._Function == _Function; }
UE_API virtual const CTypeBase* GetResultType(const CSemanticProgram& Program) const override;
};
/**
* Represents a type alias definition in the AST.
*/
class CExprTypeAliasDefinition : public CExprDefinition
{
public:
const TSRef<CTypeAlias> _TypeAlias;
UE_API CExprTypeAliasDefinition(const TSRef<CTypeAlias>& TypeAlias, TSPtr<CExpressionBase>&& Element, TSPtr<CExpressionBase>&& ValueDomain, TSPtr<CExpressionBase>&& Value, EVstMappingType = EVstMappingType::Ast);
UE_API ~CExprTypeAliasDefinition();
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Definition_TypeAlias; }
virtual CUTF8String GetErrorDesc() const override { return "type alias definition"; }
virtual bool operator==(const CExpressionBase& Other) const override { return Other.GetNodeType() == EAstNodeType::Definition_TypeAlias && static_cast<const CExprTypeAliasDefinition&>(Other)._TypeAlias == _TypeAlias; }
};
/**
* Represents a using declaration in the AST.
*/
class CExprUsing : public CExpressionBase
{
public:
// Note that not all `using` refer to a module
const CModule* _Module = nullptr;
TSRef<CExpressionBase> _Context;
CExprUsing(TSRef<CExpressionBase>&& Context) : _Context(Move(Context)) {}
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Definition_Using; }
virtual CUTF8String GetErrorDesc() const override { return "using"; }
virtual bool operator==(const CExpressionBase& Other) const override { return Other.GetNodeType() == EAstNodeType::Definition_Using && static_cast<const CExprUsing&>(Other)._Module == _Module; }
UE_API virtual const CTypeBase* GetResultType(const CSemanticProgram& Program) const override;
virtual void VisitChildren(SAstVisitor& Visitor) const override { Visitor.Visit("Context", _Context); }
UE_API virtual void VisitImmediates(SAstVisitor& Visitor) const override;
};
/**
* Represents a profile block macro invocation in the AST.
*/
class CExprProfileBlock : public CExprSubBlockBase
{
public:
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Flow_ProfileBlock; }
virtual CUTF8String GetErrorDesc() const override { return "profile"; }
virtual bool operator==(const CExpressionBase& Other) const override { return Other.GetNodeType() == EAstNodeType::Flow_ProfileBlock; }
virtual const CTypeBase* GetResultType(const CSemanticProgram& Program) const override { return _BlockExpr->GetResultType(Program); }
virtual const CExpressionBase* FindFirstAsyncSubExpr(const CSemanticProgram& Program) const override { return _BlockExpr->FindFirstAsyncSubExpr(Program); }
virtual void VisitImmediates(SAstVisitor& Visitor) const override
{
Visitor.Visit("UserTag", _UserTag);
CExprSubBlockBase::VisitImmediates(Visitor);
}
virtual void VisitChildren(SAstVisitor& Visitor) const override
{
Visitor.Visit("UserTag", _UserTag);
CExprSubBlockBase::VisitChildren(Visitor);
}
TSPtr<uLang::CExpressionBase> _UserTag; // Must resolve to a string type
#if WITH_VERSE_BPVM
const uLang::CTupleType* _ProfileLocusType;
const uLang::CTupleType* _ProfileDataType;
#endif
};
/**
* Represents a import declaration in the AST.
*/
class CExprImport : public CExpressionBase
{
public:
const TSRef<CModuleAlias> _ModuleAlias;
const TSRef<CExpressionBase> _Path;
UE_API CExprImport(const TSRef<CModuleAlias>& ModuleAlias, TSRef<CExpressionBase>&& Path, EVstMappingType VstMappingType = EVstMappingType::Ast);
UE_API ~CExprImport();
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Definition_Import; }
virtual CUTF8String GetErrorDesc() const override { return "import"; }
virtual bool operator==(const CExpressionBase& Other) const override { return Other.GetNodeType() == EAstNodeType::Definition_Import; }
UE_API virtual const CTypeBase* GetResultType(const CSemanticProgram& Program) const override;
virtual void VisitChildren(SAstVisitor& Visitor) const override { Visitor.Visit("Path", _Path); }
UE_API virtual void VisitImmediates(SAstVisitor& Visitor) const override;
};
class CExprWhere : public CExpressionBase
{
public:
CExprWhere(TSRef<CExpressionBase>&& Lhs, TSPtrArray<CExpressionBase>&& Rhs)
: _Lhs(Move(Lhs))
, _Rhs(Move(Rhs))
{
}
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Definition_Where; }
virtual CUTF8String GetErrorDesc() const override { return "where"; }
virtual bool operator==(const CExpressionBase& Right) const override
{
if (!BaseCompare(*this, Right))
{
return false;
}
const CExprWhere& RightWhere = static_cast<const CExprWhere&>(Right);
return
IsSubExprEqual(_Lhs, RightWhere._Lhs) &&
AreSubExprsEqual(_Rhs, RightWhere._Rhs);
}
virtual void VisitChildren(SAstVisitor& Visitor) const override
{
Visitor.Visit("Lhs", _Lhs);
Visitor.VisitArray("Rhs", _Rhs);
}
const TSPtr<CExpressionBase>& Lhs() const
{
return _Lhs;
}
const TSPtrArray<CExpressionBase>& Rhs() const
{
return _Rhs;
}
TSPtrArray<CExpressionBase>& Rhs()
{
return _Rhs;
}
void SetLhs(TSPtr<CExpressionBase> NewLhs)
{
_Lhs = Move(NewLhs);
}
void SetRhs(TSPtrArray<CExpressionBase> NewRhs)
{
_Rhs = Move(NewRhs);
}
private:
TSPtr<CExpressionBase> _Lhs;
TSPtrArray<CExpressionBase> _Rhs;
};
class CExprVar : public CExprUnaryOp
{
using CExprUnaryOp::CExprUnaryOp;
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Definition_Var; }
virtual bool CanFail(const CAstPackage* Package) const override { return Operand()->CanFail(Package); }
virtual CUTF8String GetErrorDesc() const override { return "var"; }
UE_API virtual bool operator==(const CExpressionBase& Other) const override;
};
/**
* Represents a named value / default value placeholder in the AST.
*/
class CExprMakeNamed : public CExpressionBase
{
public:
explicit CExprMakeNamed(const CSymbol Name)
: _Name(Name)
{
}
CExprMakeNamed(const CSymbol Name, TSPtr<CExpressionBase>&& NameIdentifier, TSPtr<CExpressionBase>&& Argument)
: _Name(Name)
, _NameIdentifier(Move(NameIdentifier))
, _Value(Move(Argument))
{
}
const CSymbol& GetName() const { return _Name; }
const TSPtr<CExpressionBase>& GetNameIdentifier() const { return _NameIdentifier; }
void SetNameIdentifier(TSPtr<CExpressionBase> NameIdentifier) { _NameIdentifier = Move(NameIdentifier); }
const TSPtr<CExpressionBase>& GetValue() const { return _Value; }
void SetValue(TSPtr<CExpressionBase> Value) { _Value = Move(Value); }
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Invoke_MakeNamed; }
virtual CUTF8String GetErrorDesc() const override { return "named"; }
virtual bool operator==(const CExpressionBase& Right) const override
{
if (!BaseCompare(*this, Right))
{
return false;
}
const CExprMakeNamed& RightNamedArgument = static_cast<const CExprMakeNamed&>(Right);
return
_Name == RightNamedArgument._Name &&
_NameIdentifier == RightNamedArgument._NameIdentifier &&
IsSubExprEqual(_Value, RightNamedArgument._Value);
}
virtual void VisitChildren(SAstVisitor& Visitor) const override
{
CExpressionBase::VisitChildren(Visitor);
Visitor.Visit("Value", _Value);
}
virtual void VisitImmediates(SAstVisitor& Visitor) const override
{
CExpressionBase::VisitImmediates(Visitor);
Visitor.VisitImmediate("Name", _Name.AsStringView());
}
virtual const CExpressionBase* FindFirstAsyncSubExpr(const CSemanticProgram& Program) const override
{
return _Value? _Value->FindFirstAsyncSubExpr(Program) : nullptr;
}
virtual bool CanFail(const CAstPackage* Package) const override
{
return _Value? _Value->CanFail(Package) : false;
}
private:
CSymbol _Name;
/// Optional pointer to the original identifier for the name. This can be used to preserve the AST
/// information about the original source text from where the identifier came from and provide context.
/// (i.e. for qualifying purposes).
TSPtr<CExpressionBase> _NameIdentifier;
TSPtr<CExpressionBase> _Value;
};
/**
* Represents a package in the AST.
**/
class CAstPackage : public CAstNode, public CMemberDefinitions
{
public:
CUTF8String _Name;
CUTF8String _VersePath; // Verse path of the root module of this package
CModulePart* _RootModule = nullptr; // Root module representing this package's Verse path
TArray<const CAstPackage*> _Dependencies; // As specified in package settings
TArray<const CAstPackage*> _UsedDependencies; // Dependencies actually used
EVerseScope _VerseScope; // Origin/visibility of Verse code in this package
EPackageRole _Role; // The role this package plays
uint32_t _EffectiveVerseVersion; // The effective language version the package targets.
/// This allows us to determine when a package was uploaded for a given Fortnite release version.
/// It is a HACK that conditionally enables/disables behaviour in the compiler in order to
/// support previous mistakes allowed to slip through in previous Verse langauge releases but
/// now need to be supported for backwards compatability.
/// When we can confirm that all Fortnite packages that are currently uploaded are beyond this
/// version being used in all instances of the codebase, this can then be removed.
uint32_t _UploadedAtFNVersion = VerseFN::UploadedAtFNVersion::Latest;
// Track the number of persistent values found on a per-package basis instead of across all packages.
int32_t _NumPersistentVars = 0;
bool _bAllowNative; // If the native attribute is allowed
bool _bTreatModulesAsImplicit; // If true, module macros in this package's source and digest will be treated as implicit
bool _bAllowExperimental; // Whether to allow the use of experimental definitions in this package.
CAstCompilationUnit* _CompilationUnit = nullptr; // Reverse pointer to our owner
CAstPackage(const CUTF8String& Name,
const CUTF8String& VersePath,
const EVerseScope VerseScope,
const EPackageRole Role,
const uint32_t EffectiveVerseVersion,
const uint32_t UploadedAtFNVersion,
const bool bAllowNative,
const bool bTreatDefinitionsAsImplicit,
const bool bAllowExperimental)
: _Name(Name)
, _VersePath(VersePath)
, _VerseScope(VerseScope)
, _Role(Role)
, _EffectiveVerseVersion(EffectiveVerseVersion)
, _UploadedAtFNVersion(UploadedAtFNVersion)
, _bAllowNative(bAllowNative)
, _bTreatModulesAsImplicit(bTreatDefinitionsAsImplicit)
, _bAllowExperimental(bAllowExperimental)
{}
// CAstNode interface.
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Context_Package; }
virtual CUTF8String GetErrorDesc() const override { return "package"; }
virtual void VisitChildren(SAstVisitor& Visitor) const override { VisitMembers(Visitor); }
UE_API virtual void VisitImmediates(SAstVisitor& Visitor) const override;
// Determine if the definition originates from this package or any of our dependencies
UE_API bool CanSeeDefinition(const CDefinition& Definition) const;
};
/**
* A group of packages that must be compiled as a unit (= a strongly connected component (SCC) in the dependency graph)
**/
class CAstCompilationUnit : public CAstNode
{
public:
const TSRefArray<CAstPackage>& Packages() const { return _Packages; }
void ReservePackages(int32_t Num) { _Packages.Reserve(Num); }
void AppendPackage(TSRef<CAstPackage>&& Package) { _Packages.Add(Move(Package)); }
UE_API EPackageRole GetRole() const;
UE_API bool IsAllowNative() const;
// CAstNode interface.
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Context_CompilationUnit; }
virtual CUTF8String GetErrorDesc() const override { return "compilation unit"; }
virtual void VisitChildren(SAstVisitor& Visitor) const override { Visitor.VisitArray("Packages", _Packages); }
private:
TSRefArray<CAstPackage> _Packages;
};
/**
* Represents a project in the AST.
**/
class CAstProject : public CAstNode
{
public:
CUTF8String _Name;
CAstProject(const CUTF8StringView& Name) : _Name(Name) {}
const TSRefArray<CAstCompilationUnit>& OrderedCompilationUnits() const { return _OrderedCompilationUnits; } // Guaranteed to be sorted in order of dependency
void ReserveCompilationUnits(int32_t Num) { _OrderedCompilationUnits.Reserve(Num); }
void AppendCompilationUnit(TSRef<CAstCompilationUnit>&& CompilationUnit) { _OrderedCompilationUnits.Add(Move(CompilationUnit)); }
UE_API const CAstPackage* FindPackageByName(const CUTF8String& PackageName) const;
UE_API int32_t GetNumPackages() const;
// CAstNode interface.
virtual EAstNodeType GetNodeType() const override { return EAstNodeType::Context_Project; }
virtual CUTF8String GetErrorDesc() const override { return "project"; }
virtual void VisitChildren(SAstVisitor& Visitor) const override { Visitor.VisitArray("CompilationUnits", _OrderedCompilationUnits); }
virtual void VisitImmediates(SAstVisitor& Visitor) const override { CAstNode::VisitImmediates(Visitor); Visitor.VisitImmediate("Name", _Name); }
private:
TSRefArray<CAstCompilationUnit> _OrderedCompilationUnits; // Guaranteed to be sorted in order of dependency
};
//=======================================================================================
// CAstNode Implementations
//=======================================================================================
template<typename FunctionType>
struct TAstFunctionVisitor : public SAstVisitor
{
FunctionType _Function;
TAstFunctionVisitor(FunctionType&& Function) : _Function(ForwardArg<FunctionType>(Function)) {}
virtual void Visit(const char* FieldName, CAstNode& AstNode) override { _Function(*this, AstNode); }
virtual void VisitElement(CAstNode& AstNode) override { _Function(*this, AstNode); }
};
template<typename FunctionType>
void CAstNode::VisitChildrenLambda(FunctionType&& Function) const
{
TAstFunctionVisitor<FunctionType> FunctionVisitor(ForwardArg<FunctionType>(Function));
VisitChildren(FunctionVisitor);
}
//=======================================================================================
// CExpressionBase Inline Methods
//=======================================================================================
//---------------------------------------------------------------------------------------
ULANG_FORCEINLINE bool CExpressionBase::IsSubExprEqual(const CExpressionBase* Lhs, const CExpressionBase* Rhs)
{
return !Lhs == !Rhs && (!Lhs || *Lhs == *Rhs);
}
ULANG_FORCEINLINE bool CExpressionBase::IsSubExprEqual(const CExpressionBase& Lhs, const CExpressionBase& Rhs)
{
return IsSubExprEqual(&Lhs, &Rhs);
}
//---------------------------------------------------------------------------------------
ULANG_FORCEINLINE bool CExpressionBase::IsSubExprEqual(const TSPtr<CExpressionBase>& Lhs, const TSPtr<CExpressionBase>& Rhs)
{
return IsSubExprEqual(Lhs.Get(), Rhs.Get());
}
//---------------------------------------------------------------------------------------
ULANG_FORCEINLINE bool CExpressionBase::IsSubExprEqual(const TSRef<CExpressionBase>& Lhs, const TSRef<CExpressionBase>& Rhs)
{
return IsSubExprEqual(Lhs.Get(), Rhs.Get());
}
//---------------------------------------------------------------------------------------
ULANG_FORCEINLINE bool CExpressionBase::AreSubExprsEqual(const TSPtrArray<CExpressionBase>& Lhs, const TSPtrArray<CExpressionBase>& Rhs)
{
if (Lhs.Num() != Rhs.Num())
{
return false;
}
for (int32_t i = 0; i < Lhs.Num(); ++i)
{
if (!IsSubExprEqual(Lhs[i], Rhs[i]))
{
return false;
}
}
return true;
}
//---------------------------------------------------------------------------------------
ULANG_FORCEINLINE bool CExpressionBase::AreSubExprsEqual(const TArray<TSPtr<CExpressionBase>>& Lhs, const TArray<TSPtr<CExpressionBase>>& Rhs)
{
if (Lhs.Num() != Rhs.Num())
{
return false;
}
for (int32_t i = 0; i < Lhs.Num(); ++i)
{
if (!IsSubExprEqual(Lhs[i], Rhs[i]))
{
return false;
}
}
return true;
}
//---------------------------------------------------------------------------------------
template <typename TIn, typename TOut>
struct TAsNullableTraitsOf;
template <typename TOut>
struct TAsNullableTraitsOf<TSPtr<CExpressionBase>, TOut>
{
using TResult = TSPtr<TOut>;
static TResult Cast(TSPtr<CExpressionBase> X) { return X.As<TOut>(); }
};
template <typename TOut>
struct TAsNullableTraitsOf<TSRef<CExpressionBase>, TOut>
{
using TResult = TSPtr<TOut>;
static TResult Cast(TSRef<CExpressionBase> X) { return X.As<TOut>(); }
};
template <typename TOut>
struct TAsNullableTraitsOf<CExpressionBase*, TOut>
{
using TResult = TOut*;
static TResult Cast(CExpressionBase* X) { return static_cast<TOut*>(X); }
};
template <typename TOut>
struct TAsNullableTraitsOf<const CExpressionBase*, TOut>
{
using TResult = const TOut*;
static TResult Cast(const CExpressionBase* X) { return static_cast<const TOut*>(X); }
};
template <typename TOut,
typename TIn,
typename Traits = TAsNullableTraitsOf<TIn, TOut>>
typename Traits::TResult AsNullable(TIn Expr)
{
#define VISIT_AST_NODE_TYPE(Name, Class) \
if constexpr (std::is_same_v<TOut, Class>) \
{ \
if (Expr && Expr->GetNodeType() == EAstNodeType::Name) \
{ \
return Traits::Cast(Expr); \
} \
}
VERSE_VISIT_AST_NODE_TYPES(VISIT_AST_NODE_TYPE)
#undef VISIT_AST_NODE_TYPE
return nullptr;
}
inline const char* AsStringLiteral(EAstNodeType Node)
{
#define VISIT_AST_NODE_TYPE(Name, Class) if (Node == EAstNodeType::Name) { return #Name; }
VERSE_VISIT_AST_NODE_TYPES(VISIT_AST_NODE_TYPE)
#undef VISIT_AST_NODE_TYPE
ULANG_UNREACHABLE();
}
} // namespace uLang
#undef UE_API