CompileResultType Compile(const TCHAR* InExpression, const FTokenDefinitions& InTokenDefinitions, const FExpressionGrammar& InGrammar)
	{
		TValueOrError<TArray<FExpressionToken>, FExpressionError> Result = Lex(InExpression, InTokenDefinitions);

		if (!Result.IsValid())
		{
			return MakeError(Result.GetError());
		}

		return Compile(MoveTemp(Result.GetValue()), InGrammar);
	}
	FExpressionResult Evaluate(const TCHAR* InExpression, const FTokenDefinitions& InTokenDefinitions, const FExpressionGrammar& InGrammar, const IOperatorEvaluationEnvironment& InEnvironment)
	{
		TValueOrError<TArray<FCompiledToken>, FExpressionError> CompilationResult = Compile(InExpression, InTokenDefinitions, InGrammar);

		if (!CompilationResult.IsValid())
		{
			return MakeError(CompilationResult.GetError());
		}

		return Evaluate(CompilationResult.GetValue(), InEnvironment);
	}
void FTextFormatData::Compile_NoLock()
{
	LexedExpression.Reset();
	if (SourceType == ESourceType::Text)
	{
		SourceExpression = SourceText.ToString();
		CompiledTextSnapshot = FTextSnapshot(SourceText);
	}
	CompiledExpressionType = FTextFormat::EExpressionType::Simple;
	BaseFormatStringLength = 0;
	FormatArgumentEstimateMultiplier = 1;

	TValueOrError<TArray<FExpressionToken>, FExpressionError> Result = ExpressionParser::Lex(*SourceExpression, FTextFormatter::Get().GetTextFormatDefinitions());
	bool bValidExpression = Result.IsValid();
	if (bValidExpression)
	{
		LexedExpression = Result.StealValue();

		// Quickly make sure the tokens are valid (argument modifiers may only follow an argument token)
		for (int32 TokenIndex = 0; TokenIndex < LexedExpression.Num(); ++TokenIndex)
		{
			const FExpressionToken& Token = LexedExpression[TokenIndex];

			if (const auto* Literal = Token.Node.Cast<TextFormatTokens::FStringLiteral>())
			{
				BaseFormatStringLength += Literal->StringLen;
			}
			else if (auto* Escaped = Token.Node.Cast<TextFormatTokens::FEscapedCharacter>())
			{
				BaseFormatStringLength += 1;
			}
			else if (const auto* ArgumentToken = Token.Node.Cast<TextFormatTokens::FArgumentTokenSpecifier>())
			{
				CompiledExpressionType = FTextFormat::EExpressionType::Complex;

				if (LexedExpression.IsValidIndex(TokenIndex + 1))
				{
					const FExpressionToken& NextToken = LexedExpression[TokenIndex + 1];

					// Peek to see if the next token is an argument modifier
					if (const auto* ArgumentModifierToken = NextToken.Node.Cast<TextFormatTokens::FArgumentModifierTokenSpecifier>())
					{
						int32 ArgModLength = 0;
						bool ArgModUsesFormatArgs = false;
						ArgumentModifierToken->TextFormatArgumentModifier->EstimateLength(ArgModLength, ArgModUsesFormatArgs);

						BaseFormatStringLength += ArgModLength;
						FormatArgumentEstimateMultiplier += (ArgModUsesFormatArgs) ? 1 : 0;

						++TokenIndex; // walk over the argument token so that the next iteration will skip over the argument modifier
						continue;
					}
				}
			}
			else if (Token.Node.Cast<TextFormatTokens::FArgumentModifierTokenSpecifier>())
			{
				// Unexpected argument modifier token!
				const FText ErrorSourceText = FText::FromString(Token.Context.GetString());
				Result = MakeError(FExpressionError(FText::Format(LOCTEXT("UnexpectedArgumentModifierToken", "Unexpected 'argument modifier' token: {0} (token started at index {1})"), ErrorSourceText, Token.Context.GetCharacterIndex())));
				bValidExpression = false;
				break;
			}
		}
	}
	
	if (!bValidExpression)
	{
		LexedExpression.Reset();
		CompiledExpressionType = FTextFormat::EExpressionType::Invalid;
		UE_LOG(LogTextFormatter, Warning, TEXT("Failed to compile text format string '%s': %s"), *SourceExpression, *Result.GetError().Text.ToString());
	}
}