mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-06-07 13:28:08 -05:00
415 lines
17 KiB
C++
415 lines
17 KiB
C++
#include "CommandsCommonMatchers.h"
|
|
|
|
#include "CommandsMatcherFactory.h"
|
|
#include "Domain/Evaluation/OperandDynamic.h"
|
|
#include "Domain/Evaluation/OperandStatic.h"
|
|
#include "Domain/Evaluation/Operation.h"
|
|
|
|
#include <list>
|
|
#include <ranges>
|
|
#include <sstream>
|
|
#include <type_traits>
|
|
#include <vector>
|
|
|
|
std::unique_ptr<CommandsCommonMatchers::matcher_t> CommandsCommonMatchers::Typename(const supplier_t* labelSupplier)
|
|
{
|
|
static constexpr const char* BUILT_IN_TYPE_NAMES[]{
|
|
"unsigned",
|
|
"char",
|
|
"short",
|
|
"int",
|
|
"long",
|
|
};
|
|
static_assert(std::extent_v<decltype(BUILT_IN_TYPE_NAMES)>
|
|
== static_cast<int>(CommandsParserValueType::BUILT_IN_LAST) - static_cast<int>(CommandsParserValueType::BUILT_IN_FIRST) + 1);
|
|
|
|
const CommandsMatcherFactory create(labelSupplier);
|
|
|
|
return create.Or({
|
|
create
|
|
.And({
|
|
create.Optional(create.Type(CommandsParserValueType::UNSIGNED)),
|
|
create.Or({
|
|
create.Type(CommandsParserValueType::CHAR),
|
|
create.Type(CommandsParserValueType::SHORT),
|
|
create.Type(CommandsParserValueType::INT),
|
|
create.And({
|
|
create.Type(CommandsParserValueType::LONG),
|
|
create.Optional(create.Type(CommandsParserValueType::LONG)),
|
|
}),
|
|
}),
|
|
})
|
|
.Transform(
|
|
[](CommandsMatcherFactory::token_list_t& values)
|
|
{
|
|
std::ostringstream str;
|
|
auto first = true;
|
|
|
|
for (const auto& token : values)
|
|
{
|
|
if (first)
|
|
first = false;
|
|
else
|
|
str << " ";
|
|
str << BUILT_IN_TYPE_NAMES[static_cast<int>(token.get().m_type) - static_cast<int>(CommandsParserValueType::BUILT_IN_FIRST)];
|
|
}
|
|
|
|
return CommandsParserValue::TypeName(values[0].get().GetPos(), new std::string(str.str()));
|
|
}),
|
|
create
|
|
.And({
|
|
create.Identifier(),
|
|
create.OptionalLoop(create.And({
|
|
create.Char(':'),
|
|
create.Char(':'),
|
|
create.Identifier(),
|
|
})),
|
|
})
|
|
.Transform(
|
|
[](CommandsMatcherFactory::token_list_t& values)
|
|
{
|
|
std::ostringstream str;
|
|
str << values[0].get().IdentifierValue();
|
|
|
|
for (auto i = 3u; i < values.size(); i += 3)
|
|
str << "::" << values[i].get().IdentifierValue();
|
|
|
|
return CommandsParserValue::TypeName(values[0].get().GetPos(), new std::string(str.str()));
|
|
}),
|
|
});
|
|
}
|
|
|
|
std::unique_ptr<CommandsCommonMatchers::matcher_t> CommandsCommonMatchers::ArrayDef(const supplier_t* labelSupplier)
|
|
{
|
|
const CommandsMatcherFactory create(labelSupplier);
|
|
|
|
return create
|
|
.And({
|
|
create.Char('['),
|
|
create.Or({
|
|
create.Integer(),
|
|
create.Identifier(),
|
|
}),
|
|
create.Char(']'),
|
|
})
|
|
.Transform(
|
|
[](CommandsMatcherFactory::token_list_t& values)
|
|
{
|
|
if (values[1].get().m_type == CommandsParserValueType::INTEGER)
|
|
return CommandsParserValue::Integer(values[1].get().GetPos(), values[1].get().IntegerValue());
|
|
|
|
return CommandsParserValue::Identifier(values[1].get().GetPos(), new std::string(values[1].get().IdentifierValue()));
|
|
});
|
|
}
|
|
|
|
static constexpr int TAG_OPERAND = std::numeric_limits<int>::max() - 1;
|
|
static constexpr int TAG_OPERAND_TYPENAME = std::numeric_limits<int>::max() - 2;
|
|
static constexpr int TAG_OPERAND_ARRAY = std::numeric_limits<int>::max() - 3;
|
|
static constexpr int TAG_OPERAND_ARRAY_END = std::numeric_limits<int>::max() - 4;
|
|
static constexpr int TAG_OPERAND_INTEGER = std::numeric_limits<int>::max() - 5;
|
|
static constexpr int TAG_EVALUATION_NOT = std::numeric_limits<int>::max() - 6;
|
|
static constexpr int TAG_EVALUATION_PARENTHESIS = std::numeric_limits<int>::max() - 7;
|
|
static constexpr int TAG_EVALUATION_PARENTHESIS_END = std::numeric_limits<int>::max() - 8;
|
|
static constexpr int TAG_EVALUATION = std::numeric_limits<int>::max() - 9;
|
|
static constexpr int TAG_EVALUATION_OPERATION = std::numeric_limits<int>::max() - 10;
|
|
|
|
static constexpr int CAPTURE_OPERAND_TYPENAME = std::numeric_limits<int>::max() - 1;
|
|
static constexpr int CAPTURE_OPERAND_ARRAY = std::numeric_limits<int>::max() - 2;
|
|
static constexpr int CAPTURE_OPERAND_INTEGER = std::numeric_limits<int>::max() - 3;
|
|
static constexpr int CAPTURE_BINARY_OPERATION_TYPE = std::numeric_limits<int>::max() - 4;
|
|
|
|
std::unique_ptr<CommandsCommonMatchers::matcher_t> CommandsCommonMatchers::ParseOperandArray(const supplier_t* labelSupplier)
|
|
{
|
|
const CommandsMatcherFactory create(labelSupplier);
|
|
|
|
return create
|
|
.And({
|
|
create.Char('['),
|
|
create.Label(LABEL_EVALUATION),
|
|
create.Char(']').Tag(TAG_OPERAND_ARRAY_END),
|
|
})
|
|
.Tag(TAG_OPERAND_ARRAY);
|
|
}
|
|
|
|
std::unique_ptr<CommandsCommonMatchers::matcher_t> CommandsCommonMatchers::ParseOperand(const supplier_t* labelSupplier)
|
|
{
|
|
const CommandsMatcherFactory create(labelSupplier);
|
|
|
|
return create
|
|
.Or({
|
|
create
|
|
.And({
|
|
create.Label(LABEL_TYPENAME).Capture(CAPTURE_OPERAND_TYPENAME),
|
|
create.OptionalLoop(MatcherFactoryWrapper<CommandsParserValue>(ParseOperandArray(labelSupplier)).Capture(CAPTURE_OPERAND_ARRAY)),
|
|
})
|
|
.Tag(TAG_OPERAND_TYPENAME),
|
|
create.Integer().Tag(TAG_OPERAND_INTEGER).Capture(CAPTURE_OPERAND_INTEGER),
|
|
})
|
|
.Tag(TAG_OPERAND);
|
|
}
|
|
|
|
std::unique_ptr<CommandsCommonMatchers::matcher_t> CommandsCommonMatchers::ParseOperationType(const supplier_t* labelSupplier)
|
|
{
|
|
const CommandsMatcherFactory create(labelSupplier);
|
|
|
|
return create
|
|
.Or({
|
|
create.Char('+').Transform(
|
|
[](CommandsMatcherFactory::token_list_t& values)
|
|
{
|
|
return CommandsParserValue::OpType(values[0].get().GetPos(), OperationType::OPERATION_ADD);
|
|
}),
|
|
create.Char('-').Transform(
|
|
[](CommandsMatcherFactory::token_list_t& values)
|
|
{
|
|
return CommandsParserValue::OpType(values[0].get().GetPos(), OperationType::OPERATION_SUBTRACT);
|
|
}),
|
|
create.Char('*').Transform(
|
|
[](CommandsMatcherFactory::token_list_t& values)
|
|
{
|
|
return CommandsParserValue::OpType(values[0].get().GetPos(), OperationType::OPERATION_MULTIPLY);
|
|
}),
|
|
create.Char('/').Transform(
|
|
[](CommandsMatcherFactory::token_list_t& values)
|
|
{
|
|
return CommandsParserValue::OpType(values[0].get().GetPos(), OperationType::OPERATION_DIVIDE);
|
|
}),
|
|
create.Char('%').Transform(
|
|
[](CommandsMatcherFactory::token_list_t& values)
|
|
{
|
|
return CommandsParserValue::OpType(values[0].get().GetPos(), OperationType::OPERATION_REMAINDER);
|
|
}),
|
|
create.Char('&').Transform(
|
|
[](CommandsMatcherFactory::token_list_t& values)
|
|
{
|
|
return CommandsParserValue::OpType(values[0].get().GetPos(), OperationType::OPERATION_BITWISE_AND);
|
|
}),
|
|
create.Char('^').Transform(
|
|
[](CommandsMatcherFactory::token_list_t& values)
|
|
{
|
|
return CommandsParserValue::OpType(values[0].get().GetPos(), OperationType::OPERATION_BITWISE_XOR);
|
|
}),
|
|
create.Char('|').Transform(
|
|
[](CommandsMatcherFactory::token_list_t& values)
|
|
{
|
|
return CommandsParserValue::OpType(values[0].get().GetPos(), OperationType::OPERATION_BITWISE_OR);
|
|
}),
|
|
create.Type(CommandsParserValueType::SHIFT_LEFT)
|
|
.Transform(
|
|
[](CommandsMatcherFactory::token_list_t& values)
|
|
{
|
|
return CommandsParserValue::OpType(values[0].get().GetPos(), OperationType::OPERATION_SHIFT_LEFT);
|
|
}),
|
|
create.Type(CommandsParserValueType::SHIFT_RIGHT)
|
|
.Transform(
|
|
[](CommandsMatcherFactory::token_list_t& values)
|
|
{
|
|
return CommandsParserValue::OpType(values[0].get().GetPos(), OperationType::OPERATION_SHIFT_RIGHT);
|
|
}),
|
|
create.Char('>').Transform(
|
|
[](CommandsMatcherFactory::token_list_t& values)
|
|
{
|
|
return CommandsParserValue::OpType(values[0].get().GetPos(), OperationType::OPERATION_GREATER_THAN);
|
|
}),
|
|
create.Type(CommandsParserValueType::GREATER_EQUAL)
|
|
.Transform(
|
|
[](CommandsMatcherFactory::token_list_t& values)
|
|
{
|
|
return CommandsParserValue::OpType(values[0].get().GetPos(), OperationType::OPERATION_GREATER_EQUAL_THAN);
|
|
}),
|
|
create.Char('<').Transform(
|
|
[](CommandsMatcherFactory::token_list_t& values)
|
|
{
|
|
return CommandsParserValue::OpType(values[0].get().GetPos(), OperationType::OPERATION_LESS_THAN);
|
|
}),
|
|
create.Type(CommandsParserValueType::LESS_EQUAL)
|
|
.Transform(
|
|
[](CommandsMatcherFactory::token_list_t& values)
|
|
{
|
|
return CommandsParserValue::OpType(values[0].get().GetPos(), OperationType::OPERATION_LESS_EQUAL_THAN);
|
|
}),
|
|
create.Type(CommandsParserValueType::EQUALS)
|
|
.Transform(
|
|
[](CommandsMatcherFactory::token_list_t& values)
|
|
{
|
|
return CommandsParserValue::OpType(values[0].get().GetPos(), OperationType::OPERATION_EQUALS);
|
|
}),
|
|
create.Type(CommandsParserValueType::NOT_EQUAL)
|
|
.Transform(
|
|
[](CommandsMatcherFactory::token_list_t& values)
|
|
{
|
|
return CommandsParserValue::OpType(values[0].get().GetPos(), OperationType::OPERATION_NOT_EQUAL);
|
|
}),
|
|
create.Type(CommandsParserValueType::LOGICAL_AND)
|
|
.Transform(
|
|
[](CommandsMatcherFactory::token_list_t& values)
|
|
{
|
|
return CommandsParserValue::OpType(values[0].get().GetPos(), OperationType::OPERATION_AND);
|
|
}),
|
|
create.Type(CommandsParserValueType::LOGICAL_OR)
|
|
.Transform(
|
|
[](CommandsMatcherFactory::token_list_t& values)
|
|
{
|
|
return CommandsParserValue::OpType(values[0].get().GetPos(), OperationType::OPERATION_OR);
|
|
}),
|
|
})
|
|
.Capture(CAPTURE_BINARY_OPERATION_TYPE);
|
|
}
|
|
|
|
std::unique_ptr<CommandsCommonMatchers::matcher_t> CommandsCommonMatchers::Evaluation(const supplier_t* labelSupplier)
|
|
{
|
|
const CommandsMatcherFactory create(labelSupplier);
|
|
|
|
return create
|
|
.And({
|
|
create.Or({
|
|
create
|
|
.And({
|
|
create.Optional(create.Char('!').Tag(TAG_EVALUATION_NOT)),
|
|
create.Char('('),
|
|
create.Label(LABEL_EVALUATION),
|
|
create.Char(')').Tag(TAG_EVALUATION_PARENTHESIS_END),
|
|
})
|
|
.Tag(TAG_EVALUATION_PARENTHESIS),
|
|
ParseOperand(labelSupplier),
|
|
}),
|
|
create.Optional(create
|
|
.And({
|
|
ParseOperationType(labelSupplier),
|
|
create.Label(LABEL_EVALUATION),
|
|
})
|
|
.Tag(TAG_EVALUATION_OPERATION)),
|
|
})
|
|
.Tag(TAG_EVALUATION);
|
|
}
|
|
|
|
std::unique_ptr<IEvaluation> CommandsCommonMatchers::ProcessEvaluationInParenthesis(CommandsParserState* state, SequenceResult<CommandsParserValue>& result)
|
|
{
|
|
const auto isNegated = result.PeekAndRemoveIfTag(TAG_EVALUATION_NOT) == TAG_EVALUATION_NOT;
|
|
|
|
auto processedEvaluation = ProcessEvaluation(state, result);
|
|
|
|
if (result.PeekAndRemoveIfTag(TAG_EVALUATION_PARENTHESIS_END) != TAG_EVALUATION_PARENTHESIS_END)
|
|
throw ParsingException(TokenPos(), "Expected parenthesis end tag @ EvaluationInParenthesis");
|
|
|
|
if (isNegated)
|
|
processedEvaluation = std::make_unique<Operation>(OperationType::OPERATION_EQUALS, std::move(processedEvaluation), std::make_unique<OperandStatic>(0));
|
|
|
|
return processedEvaluation;
|
|
}
|
|
|
|
std::unique_ptr<IEvaluation>
|
|
CommandsCommonMatchers::ProcessOperand(CommandsParserState* state, SequenceResult<CommandsParserValue>& result, StructureInformation* currentType)
|
|
{
|
|
const auto nextTag = result.NextTag();
|
|
|
|
if (nextTag == TAG_OPERAND_INTEGER)
|
|
{
|
|
return std::make_unique<OperandStatic>(result.NextCapture(CAPTURE_OPERAND_INTEGER).IntegerValue());
|
|
}
|
|
|
|
if (nextTag == TAG_OPERAND_TYPENAME)
|
|
{
|
|
const auto& typeNameToken = result.NextCapture(CAPTURE_OPERAND_TYPENAME);
|
|
std::vector<std::unique_ptr<IEvaluation>> arrayIndexEvaluations;
|
|
|
|
while (result.PeekAndRemoveIfTag(TAG_OPERAND_ARRAY) == TAG_OPERAND_ARRAY)
|
|
{
|
|
arrayIndexEvaluations.emplace_back(ProcessEvaluation(state, result, currentType));
|
|
|
|
if (result.PeekAndRemoveIfTag(TAG_OPERAND_ARRAY_END) != TAG_OPERAND_ARRAY_END)
|
|
throw ParsingException(TokenPos(), "Expected operand array end tag @ Operand");
|
|
}
|
|
|
|
auto* foundEnumMember = state->GetRepository()->GetEnumMemberByName(typeNameToken.TypeNameValue());
|
|
if (foundEnumMember != nullptr)
|
|
return std::make_unique<OperandStatic>(foundEnumMember);
|
|
|
|
StructureInformation* structure;
|
|
std::vector<MemberInformation*> memberChain;
|
|
if (state->GetTypenameAndMembersFromTypename(typeNameToken.TypeNameValue(), structure, memberChain))
|
|
return std::make_unique<OperandDynamic>(structure, std::move(memberChain), std::move(arrayIndexEvaluations));
|
|
|
|
if (currentType != nullptr && state->GetMembersFromTypename(typeNameToken.TypeNameValue(), currentType, memberChain))
|
|
return std::make_unique<OperandDynamic>(currentType, std::move(memberChain), std::move(arrayIndexEvaluations));
|
|
|
|
throw ParsingException(typeNameToken.GetPos(), "Unknown type");
|
|
}
|
|
|
|
throw ParsingException(TokenPos(), "Unknown operand type @ Operand");
|
|
}
|
|
|
|
std::unique_ptr<IEvaluation> CommandsCommonMatchers::ProcessEvaluation(CommandsParserState* state, SequenceResult<CommandsParserValue>& result)
|
|
{
|
|
return ProcessEvaluation(state, result, nullptr);
|
|
}
|
|
|
|
std::unique_ptr<IEvaluation>
|
|
CommandsCommonMatchers::ProcessEvaluation(CommandsParserState* state, SequenceResult<CommandsParserValue>& result, StructureInformation* currentType)
|
|
{
|
|
if (result.PeekAndRemoveIfTag(TAG_EVALUATION) != TAG_EVALUATION)
|
|
return nullptr;
|
|
|
|
if (currentType == state->GetInUse())
|
|
currentType = nullptr;
|
|
|
|
std::vector<std::unique_ptr<IEvaluation>> operands;
|
|
std::list<std::pair<size_t, const OperationType*>> operators;
|
|
|
|
while (true)
|
|
{
|
|
std::unique_ptr<IEvaluation> firstStatementPart;
|
|
const auto nextTag = result.NextTag();
|
|
switch (nextTag)
|
|
{
|
|
case TAG_EVALUATION_PARENTHESIS:
|
|
firstStatementPart = ProcessEvaluationInParenthesis(state, result);
|
|
break;
|
|
|
|
case TAG_OPERAND:
|
|
firstStatementPart = ProcessOperand(state, result, currentType);
|
|
break;
|
|
|
|
default:
|
|
throw ParsingException(TokenPos(), "Invalid followup tag @ Evaluation");
|
|
}
|
|
operands.emplace_back(std::move(firstStatementPart));
|
|
|
|
if (result.PeekAndRemoveIfTag(TAG_EVALUATION_OPERATION) == TAG_EVALUATION_OPERATION)
|
|
operators.emplace_back(operators.size(), result.NextCapture(CAPTURE_BINARY_OPERATION_TYPE).OpTypeValue());
|
|
else
|
|
break;
|
|
|
|
if (result.PeekAndRemoveIfTag(TAG_EVALUATION) != TAG_EVALUATION)
|
|
throw ParsingException(TokenPos(), "Expected EvaluationTag @ Evaluation");
|
|
}
|
|
|
|
operators.sort(
|
|
[](const std::pair<size_t, const OperationType*>& p1, const std::pair<size_t, const OperationType*>& p2)
|
|
{
|
|
if (p1.second->m_precedence != p2.second->m_precedence)
|
|
return p1.second->m_precedence > p2.second->m_precedence;
|
|
|
|
return p1.first > p2.first;
|
|
});
|
|
|
|
while (!operators.empty())
|
|
{
|
|
const auto [operatorIndex, operatorType] = operators.back();
|
|
|
|
auto operation = std::make_unique<Operation>(operatorType, std::move(operands[operatorIndex]), std::move(operands[operatorIndex + 1]));
|
|
operands.erase(operands.begin() + operatorIndex);
|
|
operands[operatorIndex] = std::move(operation);
|
|
|
|
operators.pop_back();
|
|
|
|
for (auto& opIndex : operators | std::views::keys)
|
|
{
|
|
if (opIndex > operatorIndex)
|
|
opIndex--;
|
|
}
|
|
}
|
|
|
|
return std::move(operands.front());
|
|
}
|