mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-04-20 00:02:55 +00:00
279 lines
12 KiB
C++
279 lines
12 KiB
C++
#include "StructuredDataDefScopeSequences.h"
|
|
|
|
#include <sstream>
|
|
|
|
#include "Parsing/Simple/Matcher/SimpleMatcherFactory.h"
|
|
|
|
namespace sdd::def_scope_sequences
|
|
{
|
|
class SequenceEnum final : public StructuredDataDefParser::sequence_t
|
|
{
|
|
static constexpr auto CAPTURE_NAME = 1;
|
|
static constexpr auto CAPTURE_RESERVED_COUNT = 2;
|
|
|
|
public:
|
|
SequenceEnum()
|
|
{
|
|
const SimpleMatcherFactory create(this);
|
|
|
|
AddMatchers({
|
|
create.Keyword("enum"),
|
|
create.Optional(create.And({
|
|
create.Char('('),
|
|
create.Integer().Capture(CAPTURE_RESERVED_COUNT),
|
|
create.Char(')')
|
|
})),
|
|
create.Identifier().Capture(CAPTURE_NAME),
|
|
create.Char('{')
|
|
});
|
|
}
|
|
|
|
protected:
|
|
void ProcessMatch(StructuredDataDefParserState* state, SequenceResult<SimpleParserValue>& result) const override
|
|
{
|
|
assert(state->m_current_def);
|
|
|
|
const auto& nameToken = result.NextCapture(CAPTURE_NAME);
|
|
auto newEnum = std::make_unique<CommonStructuredDataEnum>(nameToken.IdentifierValue());
|
|
const auto newEnumIndex = state->m_current_def->m_enums.size();
|
|
if (result.HasNextCapture(CAPTURE_RESERVED_COUNT))
|
|
{
|
|
const auto& reservedCountToken = result.NextCapture(CAPTURE_RESERVED_COUNT);
|
|
newEnum->m_reserved_entry_count = reservedCountToken.IntegerValue();
|
|
|
|
if (newEnum->m_reserved_entry_count <= 0)
|
|
throw ParsingException(reservedCountToken.GetPos(), "Reserved enum entry count must be greater than zero");
|
|
}
|
|
|
|
const auto existingType = state->m_def_types_by_name.find(newEnum->m_name);
|
|
if (existingType != state->m_def_types_by_name.end())
|
|
{
|
|
if (existingType->second.m_category == CommonStructuredDataTypeCategory::UNKNOWN)
|
|
{
|
|
assert(existingType->second.m_info.type_index < state->m_undefined_types.size());
|
|
auto& undefinedType = state->m_undefined_types[existingType->second.m_info.type_index];
|
|
undefinedType.m_mapped_type = CommonStructuredDataType(CommonStructuredDataTypeCategory::ENUM, newEnumIndex);
|
|
existingType->second = undefinedType.m_mapped_type;
|
|
}
|
|
else
|
|
throw ParsingException(nameToken.GetPos(), "Type with this name has already been defined");
|
|
}
|
|
else
|
|
state->m_def_types_by_name.emplace(newEnum->m_name, CommonStructuredDataType(CommonStructuredDataTypeCategory::ENUM, newEnumIndex));
|
|
|
|
state->m_current_enum = newEnum.get();
|
|
state->m_current_def->m_enums.emplace_back(std::move(newEnum));
|
|
}
|
|
};
|
|
|
|
class SequenceStruct final : public StructuredDataDefParser::sequence_t
|
|
{
|
|
static constexpr auto CAPTURE_NAME = 1;
|
|
|
|
public:
|
|
SequenceStruct()
|
|
{
|
|
const SimpleMatcherFactory create(this);
|
|
|
|
AddMatchers({
|
|
create.Keyword("struct"),
|
|
create.Identifier().Capture(CAPTURE_NAME),
|
|
create.Char('{')
|
|
});
|
|
}
|
|
|
|
protected:
|
|
void ProcessMatch(StructuredDataDefParserState* state, SequenceResult<SimpleParserValue>& result) const override
|
|
{
|
|
assert(state->m_current_def);
|
|
|
|
const auto& nameToken = result.NextCapture(CAPTURE_NAME);
|
|
auto newStruct = std::make_unique<CommonStructuredDataStruct>(nameToken.IdentifierValue());
|
|
auto* newStructPtr = newStruct.get();
|
|
const auto newStructIndex = state->m_current_def->m_structs.size();
|
|
|
|
const auto existingType = state->m_def_types_by_name.find(newStruct->m_name);
|
|
if (existingType != state->m_def_types_by_name.end())
|
|
{
|
|
if (existingType->second.m_category == CommonStructuredDataTypeCategory::UNKNOWN)
|
|
{
|
|
assert(existingType->second.m_info.type_index < state->m_undefined_types.size());
|
|
auto& undefinedType = state->m_undefined_types[existingType->second.m_info.type_index];
|
|
undefinedType.m_mapped_type = CommonStructuredDataType(CommonStructuredDataTypeCategory::STRUCT, newStructIndex);
|
|
existingType->second = undefinedType.m_mapped_type;
|
|
}
|
|
else
|
|
throw ParsingException(nameToken.GetPos(), "Type with this name has already been defined");
|
|
}
|
|
else
|
|
state->m_def_types_by_name.emplace(newStruct->m_name, CommonStructuredDataType(CommonStructuredDataTypeCategory::STRUCT, newStructIndex));
|
|
|
|
state->m_current_struct = newStructPtr;
|
|
state->m_current_def->m_structs.emplace_back(std::move(newStruct));
|
|
state->m_current_struct_padding_offset = 0;
|
|
|
|
if (newStructPtr->m_name == "root")
|
|
{
|
|
state->m_current_struct_padding_offset = 64u;
|
|
state->m_current_def->m_root_type = CommonStructuredDataType(CommonStructuredDataTypeCategory::STRUCT, newStructIndex);
|
|
}
|
|
else
|
|
state->m_current_struct_padding_offset = 0;
|
|
}
|
|
};
|
|
|
|
class SequenceChecksumOverride final : public StructuredDataDefParser::sequence_t
|
|
{
|
|
static constexpr auto CAPTURE_VALUE = 1;
|
|
|
|
public:
|
|
SequenceChecksumOverride()
|
|
{
|
|
const SimpleMatcherFactory create(this);
|
|
|
|
AddMatchers({
|
|
create.Keyword("checksumoverride"),
|
|
create.Integer().Capture(CAPTURE_VALUE),
|
|
create.Char(';')
|
|
});
|
|
}
|
|
|
|
protected:
|
|
void ProcessMatch(StructuredDataDefParserState* state, SequenceResult<SimpleParserValue>& result) const override
|
|
{
|
|
assert(state->m_current_def);
|
|
|
|
state->m_checksum_overriden = true;
|
|
state->m_checksum_override_value = result.NextCapture(CAPTURE_VALUE).IntegerValue();
|
|
}
|
|
};
|
|
|
|
class SequenceCloseScope final : public StructuredDataDefParser::sequence_t
|
|
{
|
|
static constexpr auto CAPTURE_NAME = 1;
|
|
|
|
public:
|
|
SequenceCloseScope()
|
|
{
|
|
const SimpleMatcherFactory create(this);
|
|
|
|
AddMatchers({
|
|
create.Char('}')
|
|
});
|
|
}
|
|
|
|
private:
|
|
static void CreateDefaultStructWhenNoStructsSpecified(const StructuredDataDefParserState* state)
|
|
{
|
|
if (state->m_current_def->m_structs.empty())
|
|
{
|
|
state->m_current_def->m_structs.emplace_back(std::make_unique<CommonStructuredDataStruct>());
|
|
state->m_current_def->m_root_type = CommonStructuredDataType(CommonStructuredDataTypeCategory::STRUCT, 0u);
|
|
}
|
|
}
|
|
|
|
static void EnsureAllUsedTypesHaveBeenDefined(const StructuredDataDefParserState* state)
|
|
{
|
|
for(const auto& undefinedType : state->m_undefined_types)
|
|
{
|
|
if (undefinedType.m_mapped_type.m_category == CommonStructuredDataTypeCategory::UNKNOWN)
|
|
{
|
|
std::ostringstream ss;
|
|
ss << "Type \"" << undefinedType.m_name << "\" has not been defined";
|
|
throw ParsingException(undefinedType.m_first_usage_pos, ss.str());
|
|
}
|
|
}
|
|
}
|
|
|
|
static void ReplaceUndefinedTypeReference(const StructuredDataDefParserState* state)
|
|
{
|
|
auto& def = *state->m_current_def;
|
|
|
|
for(const auto& _struct : def.m_structs)
|
|
{
|
|
for(auto& property : _struct->m_properties)
|
|
{
|
|
if(property.m_type.m_category == CommonStructuredDataTypeCategory::UNKNOWN)
|
|
{
|
|
assert(property.m_type.m_info.type_index < state->m_undefined_types.size());
|
|
const auto& undefinedType = state->m_undefined_types[property.m_type.m_info.type_index];
|
|
property.m_type = undefinedType.m_mapped_type;
|
|
}
|
|
}
|
|
}
|
|
|
|
for(auto& indexedArray : def.m_indexed_arrays)
|
|
{
|
|
if(indexedArray.m_array_type.m_category == CommonStructuredDataTypeCategory::UNKNOWN)
|
|
{
|
|
assert(indexedArray.m_array_type.m_info.type_index < state->m_undefined_types.size());
|
|
const auto& undefinedType = state->m_undefined_types[indexedArray.m_array_type.m_info.type_index];
|
|
indexedArray.m_array_type = undefinedType.m_mapped_type;
|
|
}
|
|
}
|
|
|
|
for(auto& enumedArray : def.m_enumed_arrays)
|
|
{
|
|
if(enumedArray.m_array_type.m_category == CommonStructuredDataTypeCategory::UNKNOWN)
|
|
{
|
|
assert(enumedArray.m_array_type.m_info.type_index < state->m_undefined_types.size());
|
|
const auto& undefinedType = state->m_undefined_types[enumedArray.m_array_type.m_info.type_index];
|
|
enumedArray.m_array_type = undefinedType.m_mapped_type;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void SetDefSizeFromRootStruct(const StructuredDataDefParserState* state)
|
|
{
|
|
if (state->m_current_def->m_root_type.m_category == CommonStructuredDataTypeCategory::STRUCT
|
|
&& state->m_current_def->m_root_type.m_info.type_index < state->m_current_def->m_structs.size())
|
|
{
|
|
const auto* _struct = state->m_current_def->m_structs[state->m_current_def->m_root_type.m_info.type_index].get();
|
|
state->m_current_def->m_size_in_byte = _struct->m_size_in_byte;
|
|
}
|
|
}
|
|
|
|
protected:
|
|
void ProcessMatch(StructuredDataDefParserState* state, SequenceResult<SimpleParserValue>& result) const override
|
|
{
|
|
assert(state->m_current_enum == nullptr);
|
|
assert(state->m_current_struct == nullptr);
|
|
|
|
CreateDefaultStructWhenNoStructsSpecified(state);
|
|
EnsureAllUsedTypesHaveBeenDefined(state);
|
|
ReplaceUndefinedTypeReference(state);
|
|
// TODO: Calculate struct sizes and property offsets
|
|
SetDefSizeFromRootStruct(state);
|
|
|
|
if (!state->m_checksum_overriden)
|
|
state->m_current_def->m_checksum = state->m_current_def->CalculateChecksum();
|
|
else
|
|
state->m_current_def->m_checksum = state->m_checksum_override_value;
|
|
|
|
state->m_current_def = nullptr;
|
|
state->m_def_types_by_name.clear();
|
|
state->m_def_indexed_arrays.clear();
|
|
state->m_def_enumed_arrays.clear();
|
|
state->m_checksum_overriden = false;
|
|
state->m_checksum_override_value = 0u;
|
|
}
|
|
};
|
|
}
|
|
|
|
using namespace sdd;
|
|
using namespace def_scope_sequences;
|
|
|
|
StructuredDataDefScopeSequences::StructuredDataDefScopeSequences(std::vector<std::unique_ptr<StructuredDataDefParser::sequence_t>>& allSequences,
|
|
std::vector<StructuredDataDefParser::sequence_t*>& scopeSequences)
|
|
: AbstractScopeSequenceHolder(allSequences, scopeSequences)
|
|
{
|
|
}
|
|
|
|
void StructuredDataDefScopeSequences::AddSequences() const
|
|
{
|
|
AddSequence(std::make_unique<SequenceCloseScope>());
|
|
AddSequence(std::make_unique<SequenceEnum>());
|
|
AddSequence(std::make_unique<SequenceStruct>());
|
|
AddSequence(std::make_unique<SequenceChecksumOverride>());
|
|
}
|