mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-07-02 09:11:49 +00:00
chore: parse includes and assetlists while parsing zone definition
This commit is contained in:
14
src/ZoneCommon/Zone/AssetList/AssetListOutputStream.cpp
Normal file
14
src/ZoneCommon/Zone/AssetList/AssetListOutputStream.cpp
Normal file
@ -0,0 +1,14 @@
|
||||
#include "AssetListOutputStream.h"
|
||||
|
||||
AssetListOutputStream::AssetListOutputStream(std::ostream& stream, const GameId game)
|
||||
: m_stream(stream),
|
||||
m_asset_name_resolver(IAssetNameResolver::GetResolverForGame(game))
|
||||
{
|
||||
}
|
||||
|
||||
void AssetListOutputStream::WriteEntry(const AssetListEntry& entry)
|
||||
{
|
||||
m_stream.WriteColumn(*m_asset_name_resolver->GetAssetTypeName(entry.m_type));
|
||||
m_stream.WriteColumn(entry.m_name);
|
||||
m_stream.NextRow();
|
||||
}
|
@ -1,23 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "AssetList.h"
|
||||
#include "Csv/CsvStream.h"
|
||||
#include "Game/IGame.h"
|
||||
#include "Zone/AssetNameResolver.h"
|
||||
|
||||
#include <Zone/AssetNameResolver.h>
|
||||
#include <iostream>
|
||||
|
||||
class AssetListInputStream
|
||||
{
|
||||
public:
|
||||
AssetListInputStream(std::istream& stream, GameId game);
|
||||
|
||||
bool NextEntry(AssetListEntry& entry, bool* failure) const;
|
||||
|
||||
private:
|
||||
CsvInputStream m_stream;
|
||||
const IAssetNameResolver* m_asset_name_resolver;
|
||||
};
|
||||
|
||||
class AssetListOutputStream
|
||||
{
|
||||
public:
|
96
src/ZoneCommon/Zone/AssetList/AssetListReader.cpp
Normal file
96
src/ZoneCommon/Zone/AssetList/AssetListReader.cpp
Normal file
@ -0,0 +1,96 @@
|
||||
#include "AssetListReader.h"
|
||||
|
||||
#include "Csv/CsvStream.h"
|
||||
#include "Game/IGame.h"
|
||||
#include "Zone/AssetNameResolver.h"
|
||||
|
||||
#include <format>
|
||||
|
||||
namespace
|
||||
{
|
||||
class AssetListInputStream
|
||||
{
|
||||
public:
|
||||
AssetListInputStream(std::istream& stream, GameId game)
|
||||
: m_stream(stream),
|
||||
m_asset_name_resolver(IAssetNameResolver::GetResolverForGame(game))
|
||||
{
|
||||
}
|
||||
|
||||
bool NextEntry(AssetListEntry& entry, bool* failure) const
|
||||
{
|
||||
std::vector<std::string> row;
|
||||
if (failure)
|
||||
*failure = false;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (!m_stream.NextRow(row))
|
||||
return false;
|
||||
|
||||
if (row.empty() || (row.size() == 1 && row[0].empty()))
|
||||
continue;
|
||||
|
||||
const auto& typeName = row[0];
|
||||
const auto maybeType = m_asset_name_resolver->GetAssetTypeByName(typeName);
|
||||
if (!maybeType)
|
||||
{
|
||||
std::cerr << std::format("Unknown asset type name \"{}\"\n", typeName);
|
||||
if (failure)
|
||||
*failure = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
entry.m_type = *maybeType;
|
||||
if (row.size() >= 3 && row[1].empty())
|
||||
{
|
||||
entry.m_name = row[2];
|
||||
entry.m_is_reference = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
entry.m_name = row[1];
|
||||
entry.m_is_reference = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
CsvInputStream m_stream;
|
||||
const IAssetNameResolver* m_asset_name_resolver;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
AssetListReader::AssetListReader(ISearchPath& searchPath, const GameId game)
|
||||
: m_search_path(searchPath),
|
||||
m_game(game)
|
||||
{
|
||||
}
|
||||
|
||||
std::optional<AssetList> AssetListReader::ReadAssetList(const std::string& zoneName, const bool logMissing) const
|
||||
{
|
||||
const auto assetListFileName = std::format("assetlist/{}.csv", zoneName);
|
||||
const auto assetListStream = m_search_path.Open(assetListFileName);
|
||||
|
||||
if (assetListStream.IsOpen())
|
||||
{
|
||||
AssetList assetList;
|
||||
const AssetListInputStream stream(*assetListStream.m_stream, m_game);
|
||||
AssetListEntry entry;
|
||||
|
||||
bool failure;
|
||||
while (stream.NextEntry(entry, &failure))
|
||||
{
|
||||
assetList.m_entries.emplace_back(std::move(entry));
|
||||
}
|
||||
|
||||
if (!failure)
|
||||
return assetList;
|
||||
}
|
||||
else if (logMissing)
|
||||
std::cerr << std::format("Failed to open file for assetlist: {}\n", assetListFileName);
|
||||
|
||||
return std::nullopt;
|
||||
}
|
20
src/ZoneCommon/Zone/AssetList/AssetListReader.h
Normal file
20
src/ZoneCommon/Zone/AssetList/AssetListReader.h
Normal file
@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include "AssetList.h"
|
||||
#include "Game/IGame.h"
|
||||
#include "SearchPath/ISearchPath.h"
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
class AssetListReader
|
||||
{
|
||||
public:
|
||||
AssetListReader(ISearchPath& searchPath, GameId game);
|
||||
|
||||
std::optional<AssetList> ReadAssetList(const std::string& zoneName, bool logMissing = true) const;
|
||||
|
||||
private:
|
||||
ISearchPath& m_search_path;
|
||||
GameId m_game;
|
||||
};
|
@ -1,62 +0,0 @@
|
||||
#include "AssetListStream.h"
|
||||
|
||||
#include <format>
|
||||
|
||||
AssetListInputStream::AssetListInputStream(std::istream& stream, const GameId game)
|
||||
: m_stream(stream),
|
||||
m_asset_name_resolver(IAssetNameResolver::GetResolverForGame(game))
|
||||
{
|
||||
}
|
||||
|
||||
bool AssetListInputStream::NextEntry(AssetListEntry& entry, bool* failure) const
|
||||
{
|
||||
std::vector<std::string> row;
|
||||
if (failure)
|
||||
*failure = false;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (!m_stream.NextRow(row))
|
||||
return false;
|
||||
|
||||
if (row.empty())
|
||||
continue;
|
||||
|
||||
const auto& typeName = row[0];
|
||||
const auto maybeType = m_asset_name_resolver->GetAssetTypeByName(typeName);
|
||||
if (!maybeType)
|
||||
{
|
||||
std::cerr << std::format("Unknown asset type name \"{}\"\n", typeName);
|
||||
if (failure)
|
||||
*failure = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
entry.m_type = *maybeType;
|
||||
if (row.size() >= 3 && row[1].empty())
|
||||
{
|
||||
entry.m_name = row[2];
|
||||
entry.m_is_reference = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
entry.m_name = row[1];
|
||||
entry.m_is_reference = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
AssetListOutputStream::AssetListOutputStream(std::ostream& stream, const GameId game)
|
||||
: m_stream(stream),
|
||||
m_asset_name_resolver(IAssetNameResolver::GetResolverForGame(game))
|
||||
{
|
||||
}
|
||||
|
||||
void AssetListOutputStream::WriteEntry(const AssetListEntry& entry)
|
||||
{
|
||||
m_stream.WriteColumn(*m_asset_name_resolver->GetAssetTypeName(entry.m_type));
|
||||
m_stream.WriteColumn(entry.m_name);
|
||||
m_stream.NextRow();
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
#include "ZoneDefinitionMatcherCharacter.h"
|
||||
|
||||
ZoneDefinitionMatcherCharacter::ZoneDefinitionMatcherCharacter(const char c)
|
||||
: m_char(c)
|
||||
{
|
||||
}
|
||||
|
||||
MatcherResult<ZoneDefinitionParserValue> ZoneDefinitionMatcherCharacter::CanMatch(ILexer<ZoneDefinitionParserValue>* lexer, const unsigned tokenOffset)
|
||||
{
|
||||
const auto& token = lexer->GetToken(tokenOffset);
|
||||
return token.m_type == ZoneDefinitionParserValueType::CHARACTER && token.CharacterValue() == m_char ? MatcherResult<ZoneDefinitionParserValue>::Match(1)
|
||||
: MatcherResult<ZoneDefinitionParserValue>::NoMatch();
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "Parsing/Matcher/AbstractMatcher.h"
|
||||
#include "Zone/Definition/Parsing/ZoneDefinitionParserValue.h"
|
||||
|
||||
class ZoneDefinitionMatcherCharacter final : public AbstractMatcher<ZoneDefinitionParserValue>
|
||||
{
|
||||
char m_char;
|
||||
|
||||
protected:
|
||||
MatcherResult<ZoneDefinitionParserValue> CanMatch(ILexer<ZoneDefinitionParserValue>* lexer, unsigned tokenOffset) override;
|
||||
|
||||
public:
|
||||
explicit ZoneDefinitionMatcherCharacter(char c);
|
||||
};
|
@ -0,0 +1,35 @@
|
||||
#include "ZoneDefinitionMatcherFactory.h"
|
||||
|
||||
#include "ZoneDefinitionMatcherCharacter.h"
|
||||
#include "ZoneDefinitionMatcherKeyword.h"
|
||||
#include "ZoneDefinitionMatcherValueType.h"
|
||||
|
||||
ZoneDefinitionMatcherFactory::ZoneDefinitionMatcherFactory(const IMatcherForLabelSupplier<ZoneDefinitionParserValue>* labelSupplier)
|
||||
: AbstractMatcherFactory(labelSupplier)
|
||||
{
|
||||
}
|
||||
|
||||
MatcherFactoryWrapper<ZoneDefinitionParserValue> ZoneDefinitionMatcherFactory::Type(ZoneDefinitionParserValueType type) const
|
||||
{
|
||||
return MatcherFactoryWrapper<ZoneDefinitionParserValue>(std::make_unique<ZoneDefinitionMatcherValueType>(type));
|
||||
}
|
||||
|
||||
MatcherFactoryWrapper<ZoneDefinitionParserValue> ZoneDefinitionMatcherFactory::Keyword(std::string keyword) const
|
||||
{
|
||||
return MatcherFactoryWrapper<ZoneDefinitionParserValue>(std::make_unique<ZoneDefinitionMatcherKeyword>(std::move(keyword)));
|
||||
}
|
||||
|
||||
MatcherFactoryWrapper<ZoneDefinitionParserValue> ZoneDefinitionMatcherFactory::Field() const
|
||||
{
|
||||
return MatcherFactoryWrapper<ZoneDefinitionParserValue>(std::make_unique<ZoneDefinitionMatcherValueType>(ZoneDefinitionParserValueType::FIELD));
|
||||
}
|
||||
|
||||
MatcherFactoryWrapper<ZoneDefinitionParserValue> ZoneDefinitionMatcherFactory::String() const
|
||||
{
|
||||
return MatcherFactoryWrapper<ZoneDefinitionParserValue>(std::make_unique<ZoneDefinitionMatcherValueType>(ZoneDefinitionParserValueType::STRING));
|
||||
}
|
||||
|
||||
MatcherFactoryWrapper<ZoneDefinitionParserValue> ZoneDefinitionMatcherFactory::Char(char c) const
|
||||
{
|
||||
return MatcherFactoryWrapper<ZoneDefinitionParserValue>(std::make_unique<ZoneDefinitionMatcherCharacter>(c));
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include "Parsing/Matcher/AbstractMatcherFactory.h"
|
||||
#include "Zone/Definition/Parsing/ZoneDefinitionParserValue.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
class ZoneDefinitionMatcherFactory final : public AbstractMatcherFactory<ZoneDefinitionParserValue>
|
||||
{
|
||||
public:
|
||||
explicit ZoneDefinitionMatcherFactory(const IMatcherForLabelSupplier<ZoneDefinitionParserValue>* labelSupplier);
|
||||
|
||||
_NODISCARD MatcherFactoryWrapper<ZoneDefinitionParserValue> Type(ZoneDefinitionParserValueType type) const;
|
||||
_NODISCARD MatcherFactoryWrapper<ZoneDefinitionParserValue> Keyword(std::string keyword) const;
|
||||
_NODISCARD MatcherFactoryWrapper<ZoneDefinitionParserValue> Field() const;
|
||||
_NODISCARD MatcherFactoryWrapper<ZoneDefinitionParserValue> String() const;
|
||||
_NODISCARD MatcherFactoryWrapper<ZoneDefinitionParserValue> Char(char c) const;
|
||||
};
|
@ -0,0 +1,16 @@
|
||||
#include "ZoneDefinitionMatcherKeyword.h"
|
||||
|
||||
ZoneDefinitionMatcherKeyword::ZoneDefinitionMatcherKeyword(std::string value)
|
||||
: m_value(std::move(value))
|
||||
{
|
||||
const std::hash<std::string> hash;
|
||||
m_hash = hash(m_value);
|
||||
}
|
||||
|
||||
MatcherResult<ZoneDefinitionParserValue> ZoneDefinitionMatcherKeyword::CanMatch(ILexer<ZoneDefinitionParserValue>* lexer, const unsigned tokenOffset)
|
||||
{
|
||||
const auto& token = lexer->GetToken(tokenOffset);
|
||||
return token.m_type == ZoneDefinitionParserValueType::FIELD && token.FieldHash() == m_hash && token.FieldValue() == m_value
|
||||
? MatcherResult<ZoneDefinitionParserValue>::Match(1)
|
||||
: MatcherResult<ZoneDefinitionParserValue>::NoMatch();
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include "Parsing/Matcher/AbstractMatcher.h"
|
||||
#include "Zone/Definition/Parsing/ZoneDefinitionParserValue.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
class ZoneDefinitionMatcherKeyword final : public AbstractMatcher<ZoneDefinitionParserValue>
|
||||
{
|
||||
size_t m_hash;
|
||||
std::string m_value;
|
||||
|
||||
protected:
|
||||
MatcherResult<ZoneDefinitionParserValue> CanMatch(ILexer<ZoneDefinitionParserValue>* lexer, unsigned tokenOffset) override;
|
||||
|
||||
public:
|
||||
explicit ZoneDefinitionMatcherKeyword(std::string value);
|
||||
};
|
@ -0,0 +1,12 @@
|
||||
#include "ZoneDefinitionMatcherValueType.h"
|
||||
|
||||
ZoneDefinitionMatcherValueType::ZoneDefinitionMatcherValueType(const ZoneDefinitionParserValueType type)
|
||||
: m_type(type)
|
||||
{
|
||||
}
|
||||
|
||||
MatcherResult<ZoneDefinitionParserValue> ZoneDefinitionMatcherValueType::CanMatch(ILexer<ZoneDefinitionParserValue>* lexer, const unsigned tokenOffset)
|
||||
{
|
||||
return lexer->GetToken(tokenOffset).m_type == m_type ? MatcherResult<ZoneDefinitionParserValue>::Match(1)
|
||||
: MatcherResult<ZoneDefinitionParserValue>::NoMatch();
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "Parsing/Matcher/AbstractMatcher.h"
|
||||
#include "Zone/Definition/Parsing/ZoneDefinitionParserValue.h"
|
||||
|
||||
class ZoneDefinitionMatcherValueType final : public AbstractMatcher<ZoneDefinitionParserValue>
|
||||
{
|
||||
ZoneDefinitionParserValueType m_type;
|
||||
|
||||
protected:
|
||||
MatcherResult<ZoneDefinitionParserValue> CanMatch(ILexer<ZoneDefinitionParserValue>* lexer, unsigned tokenOffset) override;
|
||||
|
||||
public:
|
||||
explicit ZoneDefinitionMatcherValueType(ZoneDefinitionParserValueType type);
|
||||
};
|
@ -0,0 +1,35 @@
|
||||
#include "SequenceZoneDefinitionAssetList.h"
|
||||
|
||||
#include "Zone/AssetList/AssetListReader.h"
|
||||
#include "Zone/Definition/Parsing/Matcher/ZoneDefinitionMatcherFactory.h"
|
||||
|
||||
SequenceZoneDefinitionAssetList::SequenceZoneDefinitionAssetList()
|
||||
{
|
||||
const ZoneDefinitionMatcherFactory create(this);
|
||||
|
||||
AddMatchers({
|
||||
create.Keyword("assetlist").Capture(CAPTURE_ASSET_LIST_KEYWORD),
|
||||
create.Char(','),
|
||||
create.Field().Capture(CAPTURE_ASSET_LIST_NAME),
|
||||
});
|
||||
}
|
||||
|
||||
void SequenceZoneDefinitionAssetList::ProcessMatch(ZoneDefinitionParserState* state, SequenceResult<ZoneDefinitionParserValue>& result) const
|
||||
{
|
||||
if (state->m_definition->m_game == GameId::COUNT)
|
||||
{
|
||||
const auto& assetListKeywordToken = result.NextCapture(CAPTURE_ASSET_LIST_KEYWORD);
|
||||
throw ParsingException(assetListKeywordToken.GetPos(), "Must define game before using assetlist");
|
||||
}
|
||||
|
||||
const auto& assetListNameToken = result.NextCapture(CAPTURE_ASSET_LIST_NAME);
|
||||
|
||||
AssetListReader assetListReader(state->m_search_path, state->m_definition->m_game);
|
||||
const auto maybeAssetList = assetListReader.ReadAssetList(assetListNameToken.FieldValue());
|
||||
|
||||
if (!maybeAssetList)
|
||||
throw ParsingException(assetListNameToken.GetPos(), "Failed to read asset list");
|
||||
|
||||
for (auto& assetListEntry : maybeAssetList->m_entries)
|
||||
state->m_definition->m_assets.emplace_back(assetListEntry.m_type, std::move(assetListEntry.m_name), assetListEntry.m_is_reference);
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "Zone/Definition/Parsing/ZoneDefinitionParser.h"
|
||||
|
||||
class SequenceZoneDefinitionAssetList final : public ZoneDefinitionParser::sequence_t
|
||||
{
|
||||
static constexpr auto CAPTURE_ASSET_LIST_KEYWORD = 1;
|
||||
static constexpr auto CAPTURE_ASSET_LIST_NAME = 2;
|
||||
|
||||
protected:
|
||||
void ProcessMatch(ZoneDefinitionParserState* state, SequenceResult<ZoneDefinitionParserValue>& result) const override;
|
||||
|
||||
public:
|
||||
SequenceZoneDefinitionAssetList();
|
||||
};
|
@ -0,0 +1,19 @@
|
||||
#include "SequenceZoneDefinitionBuild.h"
|
||||
|
||||
#include "Zone/Definition/Parsing/Matcher/ZoneDefinitionMatcherFactory.h"
|
||||
|
||||
SequenceZoneDefinitionBuild::SequenceZoneDefinitionBuild()
|
||||
{
|
||||
const ZoneDefinitionMatcherFactory create(this);
|
||||
|
||||
AddMatchers({
|
||||
create.Keyword("build"),
|
||||
create.Char(','),
|
||||
create.Field().Capture(CAPTURE_BUILD_TARGET_NAME),
|
||||
});
|
||||
}
|
||||
|
||||
void SequenceZoneDefinitionBuild::ProcessMatch(ZoneDefinitionParserState* state, SequenceResult<ZoneDefinitionParserValue>& result) const
|
||||
{
|
||||
state->m_definition->m_targets_to_build.emplace_back(result.NextCapture(CAPTURE_BUILD_TARGET_NAME).FieldValue());
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "Zone/Definition/Parsing/ZoneDefinitionParser.h"
|
||||
|
||||
class SequenceZoneDefinitionBuild final : public ZoneDefinitionParser::sequence_t
|
||||
{
|
||||
static constexpr auto CAPTURE_BUILD_TARGET_NAME = 1;
|
||||
|
||||
protected:
|
||||
void ProcessMatch(ZoneDefinitionParserState* state, SequenceResult<ZoneDefinitionParserValue>& result) const override;
|
||||
|
||||
public:
|
||||
SequenceZoneDefinitionBuild();
|
||||
};
|
@ -0,0 +1,41 @@
|
||||
#include "SequenceZoneDefinitionEntry.h"
|
||||
|
||||
#include "Zone/Definition/Parsing/Matcher/ZoneDefinitionMatcherFactory.h"
|
||||
|
||||
SequenceZoneDefinitionEntry::SequenceZoneDefinitionEntry()
|
||||
{
|
||||
const ZoneDefinitionMatcherFactory create(this);
|
||||
|
||||
AddMatchers({
|
||||
create.Field().Capture(CAPTURE_TYPE_NAME),
|
||||
create.Char(','),
|
||||
create.Optional(create.Char(',').Tag(TAG_REFERENCE)),
|
||||
create
|
||||
.Or({
|
||||
create.String(),
|
||||
create.Field(),
|
||||
})
|
||||
.Capture(CAPTURE_ASSET_NAME),
|
||||
});
|
||||
}
|
||||
|
||||
void SequenceZoneDefinitionEntry::ProcessMatch(ZoneDefinitionParserState* state, SequenceResult<ZoneDefinitionParserValue>& result) const
|
||||
{
|
||||
const auto& typeNameToken = result.NextCapture(CAPTURE_TYPE_NAME);
|
||||
|
||||
if (!state->m_asset_name_resolver)
|
||||
throw ParsingException(typeNameToken.GetPos(), "Must define game before first asset");
|
||||
|
||||
const auto maybeAssetType = state->m_asset_name_resolver->GetAssetTypeByName(typeNameToken.FieldValue());
|
||||
if (!maybeAssetType)
|
||||
throw ParsingException(typeNameToken.GetPos(), "Unknown asset type");
|
||||
|
||||
const auto& assetNameToken = result.NextCapture(CAPTURE_ASSET_NAME);
|
||||
std::string assetName;
|
||||
if (assetNameToken.m_type == ZoneDefinitionParserValueType::STRING)
|
||||
assetName = assetNameToken.StringValue();
|
||||
else
|
||||
assetName = assetNameToken.FieldValue();
|
||||
|
||||
state->m_definition->m_assets.emplace_back(*maybeAssetType, assetName, result.NextTag() == TAG_REFERENCE);
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include "Zone/Definition/Parsing/ZoneDefinitionParser.h"
|
||||
|
||||
class SequenceZoneDefinitionEntry final : public ZoneDefinitionParser::sequence_t
|
||||
{
|
||||
static constexpr auto TAG_REFERENCE = 1;
|
||||
|
||||
static constexpr auto CAPTURE_TYPE_NAME = 1;
|
||||
static constexpr auto CAPTURE_ASSET_NAME = 2;
|
||||
|
||||
protected:
|
||||
void ProcessMatch(ZoneDefinitionParserState* state, SequenceResult<ZoneDefinitionParserValue>& result) const override;
|
||||
|
||||
public:
|
||||
SequenceZoneDefinitionEntry();
|
||||
};
|
@ -0,0 +1,19 @@
|
||||
#include "SequenceZoneDefinitionIgnore.h"
|
||||
|
||||
#include "Zone/Definition/Parsing/Matcher/ZoneDefinitionMatcherFactory.h"
|
||||
|
||||
SequenceZoneDefinitionIgnore::SequenceZoneDefinitionIgnore()
|
||||
{
|
||||
const ZoneDefinitionMatcherFactory create(this);
|
||||
|
||||
AddMatchers({
|
||||
create.Keyword("ignore"),
|
||||
create.Char(','),
|
||||
create.Field().Capture(CAPTURE_IGNORE_NAME),
|
||||
});
|
||||
}
|
||||
|
||||
void SequenceZoneDefinitionIgnore::ProcessMatch(ZoneDefinitionParserState* state, SequenceResult<ZoneDefinitionParserValue>& result) const
|
||||
{
|
||||
state->m_definition->m_ignores.emplace_back(result.NextCapture(CAPTURE_IGNORE_NAME).FieldValue());
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "Zone/Definition/Parsing/ZoneDefinitionParser.h"
|
||||
|
||||
class SequenceZoneDefinitionIgnore final : public ZoneDefinitionParser::sequence_t
|
||||
{
|
||||
static constexpr auto CAPTURE_IGNORE_NAME = 1;
|
||||
|
||||
protected:
|
||||
void ProcessMatch(ZoneDefinitionParserState* state, SequenceResult<ZoneDefinitionParserValue>& result) const override;
|
||||
|
||||
public:
|
||||
SequenceZoneDefinitionIgnore();
|
||||
};
|
@ -0,0 +1,32 @@
|
||||
#include "SequenceZoneDefinitionInclude.h"
|
||||
|
||||
#include "Zone/Definition/Parsing/Matcher/ZoneDefinitionMatcherFactory.h"
|
||||
|
||||
#include <format>
|
||||
|
||||
SequenceZoneDefinitionInclude::SequenceZoneDefinitionInclude()
|
||||
{
|
||||
const ZoneDefinitionMatcherFactory create(this);
|
||||
|
||||
AddMatchers({
|
||||
create.Keyword("include"),
|
||||
create.Char(','),
|
||||
create.Field().Capture(CAPTURE_INCLUDE_NAME),
|
||||
});
|
||||
}
|
||||
|
||||
void SequenceZoneDefinitionInclude::ProcessMatch(ZoneDefinitionParserState* state, SequenceResult<ZoneDefinitionParserValue>& result) const
|
||||
{
|
||||
const auto& inclusionNameToken = result.NextCapture(CAPTURE_INCLUDE_NAME);
|
||||
const auto inclusionName = inclusionNameToken.FieldValue();
|
||||
const auto existingInclusion = state->m_inclusions.find(inclusionName);
|
||||
if (existingInclusion != state->m_inclusions.end())
|
||||
throw ParsingException(inclusionNameToken.GetPos(), "Zone definition has already been included");
|
||||
|
||||
const auto zoneDefinitionFileNameToInclude = std::format("{}.zone", inclusionName);
|
||||
|
||||
if (!state->m_underlying_stream.IncludeFile(zoneDefinitionFileNameToInclude))
|
||||
throw ParsingException(inclusionNameToken.GetPos(), "Could not find zone definition with this filename");
|
||||
|
||||
state->m_inclusions.emplace(inclusionName);
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "Zone/Definition/Parsing/ZoneDefinitionParser.h"
|
||||
|
||||
class SequenceZoneDefinitionInclude final : public ZoneDefinitionParser::sequence_t
|
||||
{
|
||||
static constexpr auto CAPTURE_INCLUDE_NAME = 1;
|
||||
|
||||
protected:
|
||||
void ProcessMatch(ZoneDefinitionParserState* state, SequenceResult<ZoneDefinitionParserValue>& result) const override;
|
||||
|
||||
public:
|
||||
SequenceZoneDefinitionInclude();
|
||||
};
|
@ -0,0 +1,166 @@
|
||||
#include "SequenceZoneDefinitionMetaData.h"
|
||||
|
||||
#include "Utils/StringUtils.h"
|
||||
#include "Zone/Definition/Parsing/Matcher/ZoneDefinitionMatcherFactory.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <format>
|
||||
#include <optional>
|
||||
|
||||
namespace
|
||||
{
|
||||
constexpr auto METADATA_GAME = "game";
|
||||
constexpr auto METADATA_GDT = "gdt";
|
||||
constexpr auto METADATA_NAME = "name";
|
||||
constexpr auto METADATA_TYPE = "type";
|
||||
|
||||
constexpr auto METADATA_IPAK = "ipak";
|
||||
constexpr auto METADATA_IWD = "iwd";
|
||||
|
||||
std::optional<GameId> GetGameByName(const std::string& gameName)
|
||||
{
|
||||
auto upperGameName = gameName;
|
||||
utils::MakeStringUpperCase(upperGameName);
|
||||
|
||||
for (auto i = 0u; i < static_cast<unsigned>(GameId::COUNT); i++)
|
||||
{
|
||||
if (upperGameName == GameId_Names[i])
|
||||
return static_cast<GameId>(i);
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
enum class ProjectType : std::uint8_t
|
||||
{
|
||||
NONE,
|
||||
FASTFILE,
|
||||
IPAK,
|
||||
|
||||
COUNT
|
||||
};
|
||||
constexpr const char* ProjectType_Names[]{
|
||||
"none",
|
||||
"fastfile",
|
||||
"ipak",
|
||||
};
|
||||
static_assert(std::extent_v<decltype(ProjectType_Names)> == static_cast<unsigned>(ProjectType::COUNT));
|
||||
|
||||
std::optional<ProjectType> GetProjectTypeByName(const std::string& projectTypeName)
|
||||
{
|
||||
auto lowerProjectTypeName = projectTypeName;
|
||||
utils::MakeStringLowerCase(lowerProjectTypeName);
|
||||
|
||||
for (auto i = 0u; i < static_cast<unsigned>(ProjectType::COUNT); i++)
|
||||
{
|
||||
if (lowerProjectTypeName == ProjectType_Names[i])
|
||||
return static_cast<ProjectType>(i);
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
SequenceZoneDefinitionMetaData::SequenceZoneDefinitionMetaData()
|
||||
{
|
||||
const ZoneDefinitionMatcherFactory create(this);
|
||||
|
||||
AddMatchers({
|
||||
create.Char('>'),
|
||||
create.Field().Capture(CAPTURE_KEY),
|
||||
create.Char(','),
|
||||
create.Field().Capture(CAPTURE_VALUE),
|
||||
});
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
void ProcessMetaDataGame(ZoneDefinitionParserState* state, const ZoneDefinitionParserValue& valueToken, const std::string& value)
|
||||
{
|
||||
const auto game = GetGameByName(value);
|
||||
if (!game)
|
||||
throw ParsingException(valueToken.GetPos(), "Unknown game name");
|
||||
|
||||
const auto previousGame = state->m_definition->m_game;
|
||||
if (previousGame != GameId::COUNT && previousGame != *game)
|
||||
throw ParsingException(valueToken.GetPos(), std::format("Game was previously defined as: {}", GameId_Names[static_cast<unsigned>(previousGame)]));
|
||||
|
||||
state->SetGame(*game);
|
||||
}
|
||||
|
||||
void ProcessMetaDataType(ZoneDefinitionParserState* state, const ZoneDefinitionParserValue& keyToken, const ZoneDefinitionParserValue& valueToken)
|
||||
{
|
||||
const auto projectType = GetProjectTypeByName(valueToken.FieldValue());
|
||||
if (!projectType)
|
||||
throw ParsingException(valueToken.GetPos(), "Unknown project type name");
|
||||
|
||||
// TODO: Remove deprecated type
|
||||
|
||||
std::string deprecationSuggestedAction;
|
||||
if (*projectType == ProjectType::IPAK)
|
||||
{
|
||||
deprecationSuggestedAction = "Use \">ipak,name_of_ipak\" instead.";
|
||||
state->StartIPak(state->m_definition->m_name);
|
||||
}
|
||||
else if (*projectType == ProjectType::FASTFILE)
|
||||
{
|
||||
deprecationSuggestedAction = "A fastfile will always be built when appropriate assets have been added.";
|
||||
}
|
||||
else
|
||||
{
|
||||
deprecationSuggestedAction = "It now has no effect.";
|
||||
}
|
||||
|
||||
const auto keyPos = keyToken.GetPos();
|
||||
std::cerr << std::format("Warning: {} L{}: Zone definition \">type,{}\" is deprecated and should be removed. {}\n",
|
||||
keyPos.m_filename.get(),
|
||||
keyPos.m_line,
|
||||
keyToken.FieldValue(),
|
||||
deprecationSuggestedAction);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void SequenceZoneDefinitionMetaData::ProcessMatch(ZoneDefinitionParserState* state, SequenceResult<ZoneDefinitionParserValue>& result) const
|
||||
{
|
||||
const auto& keyToken = result.NextCapture(CAPTURE_KEY);
|
||||
auto key = keyToken.FieldValue();
|
||||
const auto& valueToken = result.NextCapture(CAPTURE_VALUE);
|
||||
const auto& value = valueToken.FieldValue();
|
||||
|
||||
utils::MakeStringLowerCase(key);
|
||||
|
||||
if (key == METADATA_GAME)
|
||||
{
|
||||
ProcessMetaDataGame(state, valueToken, value);
|
||||
}
|
||||
else if (key == METADATA_GDT)
|
||||
{
|
||||
state->m_definition->m_gdts.emplace_back(value);
|
||||
}
|
||||
else if (key == METADATA_NAME)
|
||||
{
|
||||
state->m_definition->m_name = value;
|
||||
}
|
||||
else if (key == METADATA_TYPE)
|
||||
{
|
||||
ProcessMetaDataType(state, keyToken, valueToken);
|
||||
}
|
||||
else if (key == METADATA_IPAK)
|
||||
{
|
||||
if (!value.empty())
|
||||
state->StartIPak(value);
|
||||
else
|
||||
throw ParsingException(valueToken.GetPos(), "IPak must have a name");
|
||||
}
|
||||
else if (key == METADATA_IWD)
|
||||
{
|
||||
if (!value.empty())
|
||||
state->StartIwd(value);
|
||||
else
|
||||
throw ParsingException(valueToken.GetPos(), "IWD must have a name");
|
||||
}
|
||||
else
|
||||
{
|
||||
state->m_definition->m_properties.AddProperty(key, value);
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "Zone/Definition/Parsing/ZoneDefinitionParser.h"
|
||||
|
||||
class SequenceZoneDefinitionMetaData final : public ZoneDefinitionParser::sequence_t
|
||||
{
|
||||
static constexpr auto CAPTURE_KEY = 1;
|
||||
static constexpr auto CAPTURE_VALUE = 2;
|
||||
|
||||
protected:
|
||||
void ProcessMatch(ZoneDefinitionParserState* state, SequenceResult<ZoneDefinitionParserValue>& result) const override;
|
||||
|
||||
public:
|
||||
SequenceZoneDefinitionMetaData();
|
||||
};
|
@ -0,0 +1,75 @@
|
||||
#include "ZoneDefinitionLexer.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
ZoneDefinitionLexer::ZoneDefinitionLexer(IParserLineStream* stream)
|
||||
: AbstractLexer(stream)
|
||||
{
|
||||
}
|
||||
|
||||
std::string ZoneDefinitionLexer::ReadField()
|
||||
{
|
||||
const auto& currentLine = CurrentLine();
|
||||
assert(m_current_line_offset >= 1);
|
||||
|
||||
const auto startPos = m_current_line_offset - 1;
|
||||
const auto lineSize = currentLine.m_line.size();
|
||||
auto lastNonSpaceOffset = m_current_line_offset;
|
||||
while (m_current_line_offset < lineSize)
|
||||
{
|
||||
const auto c = currentLine.m_line[m_current_line_offset];
|
||||
|
||||
bool isNonFieldCharacter;
|
||||
switch (c)
|
||||
{
|
||||
case '\"':
|
||||
case '>':
|
||||
case '<':
|
||||
case ',':
|
||||
isNonFieldCharacter = true;
|
||||
break;
|
||||
default:
|
||||
isNonFieldCharacter = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (isNonFieldCharacter)
|
||||
break;
|
||||
|
||||
m_current_line_offset++;
|
||||
|
||||
if (!isspace(c))
|
||||
lastNonSpaceOffset = m_current_line_offset;
|
||||
}
|
||||
|
||||
return std::string(currentLine.m_line, startPos, lastNonSpaceOffset - startPos);
|
||||
}
|
||||
|
||||
ZoneDefinitionParserValue ZoneDefinitionLexer::GetNextToken()
|
||||
{
|
||||
auto c = NextChar();
|
||||
|
||||
while (c != EOF)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '\"':
|
||||
return ZoneDefinitionParserValue::String(GetPreviousCharacterPos(), new std::string(ReadString()));
|
||||
|
||||
case '>':
|
||||
case '<':
|
||||
case ',':
|
||||
return ZoneDefinitionParserValue::Character(GetPreviousCharacterPos(), static_cast<char>(c));
|
||||
|
||||
default:
|
||||
if (isspace(c))
|
||||
break;
|
||||
|
||||
return ZoneDefinitionParserValue::Field(GetPreviousCharacterPos(), new std::string(ReadField()));
|
||||
}
|
||||
|
||||
c = NextChar();
|
||||
}
|
||||
|
||||
return ZoneDefinitionParserValue::EndOfFile(TokenPos());
|
||||
}
|
15
src/ZoneCommon/Zone/Definition/Parsing/ZoneDefinitionLexer.h
Normal file
15
src/ZoneCommon/Zone/Definition/Parsing/ZoneDefinitionLexer.h
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "Parsing/Impl/AbstractLexer.h"
|
||||
#include "ZoneDefinitionParserValue.h"
|
||||
|
||||
class ZoneDefinitionLexer final : public AbstractLexer<ZoneDefinitionParserValue>
|
||||
{
|
||||
std::string ReadField();
|
||||
|
||||
protected:
|
||||
ZoneDefinitionParserValue GetNextToken() override;
|
||||
|
||||
public:
|
||||
explicit ZoneDefinitionLexer(IParserLineStream* stream);
|
||||
};
|
@ -0,0 +1,35 @@
|
||||
#include "ZoneDefinitionParser.h"
|
||||
|
||||
#include "Sequence/SequenceZoneDefinitionAssetList.h"
|
||||
#include "Sequence/SequenceZoneDefinitionBuild.h"
|
||||
#include "Sequence/SequenceZoneDefinitionEntry.h"
|
||||
#include "Sequence/SequenceZoneDefinitionIgnore.h"
|
||||
#include "Sequence/SequenceZoneDefinitionInclude.h"
|
||||
#include "Sequence/SequenceZoneDefinitionMetaData.h"
|
||||
|
||||
ZoneDefinitionParser::ZoneDefinitionParser(
|
||||
ZoneDefinitionLexer* lexer, std::string targetName, ISearchPath& searchPath, IParserLineStream& underlyingStream, const std::optional<GameId> maybeGame)
|
||||
: AbstractParser(lexer, std::make_unique<ZoneDefinitionParserState>(std::move(targetName), searchPath, underlyingStream))
|
||||
{
|
||||
if (maybeGame)
|
||||
m_state->SetGame(*maybeGame);
|
||||
}
|
||||
|
||||
const std::vector<AbstractParser<ZoneDefinitionParserValue, ZoneDefinitionParserState>::sequence_t*>& ZoneDefinitionParser::GetTestsForState()
|
||||
{
|
||||
static std::vector<sequence_t*> tests({
|
||||
new SequenceZoneDefinitionMetaData(),
|
||||
new SequenceZoneDefinitionInclude(),
|
||||
new SequenceZoneDefinitionIgnore(),
|
||||
new SequenceZoneDefinitionAssetList(),
|
||||
new SequenceZoneDefinitionBuild(),
|
||||
new SequenceZoneDefinitionEntry(),
|
||||
});
|
||||
|
||||
return tests;
|
||||
}
|
||||
|
||||
std::unique_ptr<ZoneDefinition> ZoneDefinitionParser::GetParsedValue()
|
||||
{
|
||||
return std::move(m_state->m_definition);
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include "Game/IGame.h"
|
||||
#include "Parsing/Impl/AbstractParser.h"
|
||||
#include "SearchPath/ISearchPath.h"
|
||||
#include "Zone/Definition/ZoneDefinition.h"
|
||||
#include "ZoneDefinitionLexer.h"
|
||||
#include "ZoneDefinitionParserState.h"
|
||||
#include "ZoneDefinitionParserValue.h"
|
||||
|
||||
#include <optional>
|
||||
|
||||
class ZoneDefinitionParser final : public AbstractParser<ZoneDefinitionParserValue, ZoneDefinitionParserState>
|
||||
{
|
||||
public:
|
||||
ZoneDefinitionParser(ZoneDefinitionLexer* lexer,
|
||||
std::string targetName,
|
||||
ISearchPath& searchPath,
|
||||
IParserLineStream& underlyingStream,
|
||||
std::optional<GameId> maybeGame = std::nullopt);
|
||||
std::unique_ptr<ZoneDefinition> GetParsedValue();
|
||||
|
||||
protected:
|
||||
const std::vector<sequence_t*>& GetTestsForState() override;
|
||||
};
|
@ -0,0 +1,67 @@
|
||||
#include "ZoneDefinitionParserState.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
ZoneDefinitionParserState::ZoneDefinitionParserState(std::string targetName, ISearchPath& searchPath, IParserLineStream& underlyingStream)
|
||||
: m_search_path(searchPath),
|
||||
m_underlying_stream(underlyingStream),
|
||||
m_asset_name_resolver(nullptr),
|
||||
m_definition(std::make_unique<ZoneDefinition>())
|
||||
|
||||
{
|
||||
m_inclusions.emplace(targetName);
|
||||
m_definition->m_name = std::move(targetName);
|
||||
}
|
||||
|
||||
void ZoneDefinitionParserState::SetGame(const GameId game)
|
||||
{
|
||||
m_definition->m_game = game;
|
||||
m_asset_name_resolver = IAssetNameResolver::GetResolverForGame(game);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
void AddCurrentObjContainerToDefinitionIfNecessary(ZoneDefinition& zoneDefinition, std::optional<ZoneDefinitionObjContainer>& maybeObjContainer)
|
||||
{
|
||||
if (!maybeObjContainer)
|
||||
return;
|
||||
|
||||
maybeObjContainer->m_asset_end = zoneDefinition.m_assets.size();
|
||||
zoneDefinition.m_obj_containers.emplace_back(std::move(*maybeObjContainer));
|
||||
maybeObjContainer = std::nullopt;
|
||||
}
|
||||
|
||||
ZoneDefinitionObjContainer DefineNewObjContainer(const ZoneDefinition& zoneDefinition, std::string name, const ZoneDefinitionObjContainerType type)
|
||||
{
|
||||
return ZoneDefinitionObjContainer(std::move(name), type, zoneDefinition.m_assets.size());
|
||||
}
|
||||
|
||||
void SortObjContainer(ZoneDefinition& zoneDefinition)
|
||||
{
|
||||
std::ranges::sort(zoneDefinition.m_obj_containers,
|
||||
[](const ZoneDefinitionObjContainer& obj0, const ZoneDefinitionObjContainer& obj1)
|
||||
{
|
||||
return obj0.m_asset_start < obj1.m_asset_start;
|
||||
});
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void ZoneDefinitionParserState::StartIPak(std::string ipakName)
|
||||
{
|
||||
AddCurrentObjContainerToDefinitionIfNecessary(*m_definition, m_current_ipak);
|
||||
m_current_ipak = DefineNewObjContainer(*m_definition, std::move(ipakName), ZoneDefinitionObjContainerType::IPAK);
|
||||
}
|
||||
|
||||
void ZoneDefinitionParserState::StartIwd(std::string iwdName)
|
||||
{
|
||||
AddCurrentObjContainerToDefinitionIfNecessary(*m_definition, m_current_iwd);
|
||||
m_current_iwd = DefineNewObjContainer(*m_definition, std::move(iwdName), ZoneDefinitionObjContainerType::IWD);
|
||||
}
|
||||
|
||||
void ZoneDefinitionParserState::Finalize()
|
||||
{
|
||||
AddCurrentObjContainerToDefinitionIfNecessary(*m_definition, m_current_ipak);
|
||||
AddCurrentObjContainerToDefinitionIfNecessary(*m_definition, m_current_iwd);
|
||||
|
||||
SortObjContainer(*m_definition);
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include "Parsing/IParserLineStream.h"
|
||||
#include "SearchPath/ISearchPath.h"
|
||||
#include "Zone/AssetNameResolver.h"
|
||||
#include "Zone/Definition/ZoneDefinition.h"
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
|
||||
class ZoneDefinitionParserState
|
||||
{
|
||||
public:
|
||||
ZoneDefinitionParserState(std::string targetName, ISearchPath& searchPath, IParserLineStream& underlyingStream);
|
||||
|
||||
void SetGame(GameId game);
|
||||
|
||||
void StartIPak(std::string ipakName);
|
||||
void StartIwd(std::string iwdName);
|
||||
|
||||
void Finalize();
|
||||
|
||||
ISearchPath& m_search_path;
|
||||
IParserLineStream& m_underlying_stream;
|
||||
std::unordered_set<std::string> m_inclusions;
|
||||
|
||||
const IAssetNameResolver* m_asset_name_resolver;
|
||||
|
||||
std::optional<ZoneDefinitionObjContainer> m_current_ipak;
|
||||
std::optional<ZoneDefinitionObjContainer> m_current_iwd;
|
||||
|
||||
std::unique_ptr<ZoneDefinition> m_definition;
|
||||
};
|
@ -0,0 +1,115 @@
|
||||
#include "ZoneDefinitionParserValue.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
ZoneDefinitionParserValue ZoneDefinitionParserValue::Invalid(const TokenPos pos)
|
||||
{
|
||||
ZoneDefinitionParserValue pv(pos, ZoneDefinitionParserValueType::INVALID);
|
||||
return pv;
|
||||
}
|
||||
|
||||
ZoneDefinitionParserValue ZoneDefinitionParserValue::EndOfFile(const TokenPos pos)
|
||||
{
|
||||
ZoneDefinitionParserValue pv(pos, ZoneDefinitionParserValueType::END_OF_FILE);
|
||||
return pv;
|
||||
}
|
||||
|
||||
ZoneDefinitionParserValue ZoneDefinitionParserValue::Character(const TokenPos pos, const char c)
|
||||
{
|
||||
ZoneDefinitionParserValue pv(pos, ZoneDefinitionParserValueType::CHARACTER);
|
||||
pv.m_value.char_value = c;
|
||||
return pv;
|
||||
}
|
||||
|
||||
ZoneDefinitionParserValue ZoneDefinitionParserValue::String(const TokenPos pos, std::string* str)
|
||||
{
|
||||
ZoneDefinitionParserValue pv(pos, ZoneDefinitionParserValueType::STRING);
|
||||
pv.m_value.string_value = str;
|
||||
return pv;
|
||||
}
|
||||
|
||||
ZoneDefinitionParserValue ZoneDefinitionParserValue::Field(const TokenPos pos, std::string* field)
|
||||
{
|
||||
ZoneDefinitionParserValue pv(pos, ZoneDefinitionParserValueType::FIELD);
|
||||
pv.m_value.string_value = field;
|
||||
pv.m_hash = std::hash<std::string>()(*field);
|
||||
return pv;
|
||||
}
|
||||
|
||||
ZoneDefinitionParserValue::ZoneDefinitionParserValue(const TokenPos pos, const ZoneDefinitionParserValueType type)
|
||||
: m_pos(pos),
|
||||
m_type(type),
|
||||
m_hash(0),
|
||||
m_value{}
|
||||
{
|
||||
}
|
||||
|
||||
ZoneDefinitionParserValue::~ZoneDefinitionParserValue()
|
||||
{
|
||||
switch (m_type)
|
||||
{
|
||||
case ZoneDefinitionParserValueType::STRING:
|
||||
case ZoneDefinitionParserValueType::FIELD:
|
||||
delete m_value.string_value;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
m_value = ValueType();
|
||||
}
|
||||
|
||||
ZoneDefinitionParserValue::ZoneDefinitionParserValue(ZoneDefinitionParserValue&& other) noexcept
|
||||
: m_pos(other.m_pos),
|
||||
m_type(other.m_type),
|
||||
m_hash(other.m_hash),
|
||||
m_value(other.m_value)
|
||||
{
|
||||
other.m_value = ValueType();
|
||||
}
|
||||
|
||||
ZoneDefinitionParserValue& ZoneDefinitionParserValue::operator=(ZoneDefinitionParserValue&& other) noexcept
|
||||
{
|
||||
m_pos = other.m_pos;
|
||||
m_type = other.m_type;
|
||||
m_value = other.m_value;
|
||||
m_hash = other.m_hash;
|
||||
other.m_value = ValueType();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool ZoneDefinitionParserValue::IsEof() const
|
||||
{
|
||||
return m_type == ZoneDefinitionParserValueType::END_OF_FILE;
|
||||
}
|
||||
|
||||
const TokenPos& ZoneDefinitionParserValue::GetPos() const
|
||||
{
|
||||
return m_pos;
|
||||
}
|
||||
|
||||
char ZoneDefinitionParserValue::CharacterValue() const
|
||||
{
|
||||
assert(m_type == ZoneDefinitionParserValueType::CHARACTER);
|
||||
return m_value.char_value;
|
||||
}
|
||||
|
||||
std::string& ZoneDefinitionParserValue::StringValue() const
|
||||
{
|
||||
assert(m_type == ZoneDefinitionParserValueType::STRING);
|
||||
return *m_value.string_value;
|
||||
}
|
||||
|
||||
std::string& ZoneDefinitionParserValue::FieldValue() const
|
||||
{
|
||||
assert(m_type == ZoneDefinitionParserValueType::FIELD);
|
||||
return *m_value.string_value;
|
||||
}
|
||||
|
||||
size_t ZoneDefinitionParserValue::FieldHash() const
|
||||
{
|
||||
assert(m_type == ZoneDefinitionParserValueType::FIELD);
|
||||
return m_hash;
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
|
||||
#include "Parsing/IParserValue.h"
|
||||
#include "Parsing/TokenPos.h"
|
||||
#include "Utils/ClassUtils.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
enum class ZoneDefinitionParserValueType
|
||||
{
|
||||
// Meta tokens
|
||||
INVALID,
|
||||
END_OF_FILE,
|
||||
|
||||
CHARACTER,
|
||||
STRING,
|
||||
FIELD,
|
||||
|
||||
// End
|
||||
MAX
|
||||
};
|
||||
|
||||
class ZoneDefinitionParserValue final : public IParserValue
|
||||
{
|
||||
public:
|
||||
TokenPos m_pos;
|
||||
ZoneDefinitionParserValueType m_type;
|
||||
size_t m_hash;
|
||||
|
||||
union ValueType
|
||||
{
|
||||
char char_value;
|
||||
std::string* string_value;
|
||||
} m_value;
|
||||
|
||||
static ZoneDefinitionParserValue Invalid(TokenPos pos);
|
||||
static ZoneDefinitionParserValue EndOfFile(TokenPos pos);
|
||||
static ZoneDefinitionParserValue Character(TokenPos pos, char c);
|
||||
static ZoneDefinitionParserValue String(TokenPos pos, std::string* str);
|
||||
static ZoneDefinitionParserValue Field(TokenPos pos, std::string* field);
|
||||
|
||||
private:
|
||||
ZoneDefinitionParserValue(TokenPos pos, ZoneDefinitionParserValueType type);
|
||||
|
||||
public:
|
||||
~ZoneDefinitionParserValue() override;
|
||||
ZoneDefinitionParserValue(const ZoneDefinitionParserValue& other) = delete;
|
||||
ZoneDefinitionParserValue(ZoneDefinitionParserValue&& other) noexcept;
|
||||
ZoneDefinitionParserValue& operator=(const ZoneDefinitionParserValue& other) = delete;
|
||||
ZoneDefinitionParserValue& operator=(ZoneDefinitionParserValue&& other) noexcept;
|
||||
|
||||
_NODISCARD bool IsEof() const override;
|
||||
_NODISCARD const TokenPos& GetPos() const override;
|
||||
|
||||
_NODISCARD char CharacterValue() const;
|
||||
_NODISCARD std::string& StringValue() const;
|
||||
_NODISCARD std::string& FieldValue() const;
|
||||
_NODISCARD size_t FieldHash() const;
|
||||
};
|
@ -32,20 +32,3 @@ ZoneDefinition::ZoneDefinition()
|
||||
: m_game(GameId::COUNT)
|
||||
{
|
||||
}
|
||||
|
||||
void ZoneDefinition::Include(const AssetList& assetListToInclude)
|
||||
{
|
||||
for (const auto& entry : assetListToInclude.m_entries)
|
||||
m_assets.emplace_back(entry.m_type, entry.m_name, false);
|
||||
}
|
||||
|
||||
void ZoneDefinition::Include(const ZoneDefinition& definitionToInclude)
|
||||
{
|
||||
m_properties.Include(definitionToInclude.m_properties);
|
||||
|
||||
for (const auto& ignore : definitionToInclude.m_ignores)
|
||||
m_ignores.emplace_back(ignore);
|
||||
|
||||
for (const auto& asset : definitionToInclude.m_assets)
|
||||
m_assets.emplace_back(asset);
|
||||
}
|
||||
|
@ -60,14 +60,9 @@ class ZoneDefinition
|
||||
public:
|
||||
ZoneDefinition();
|
||||
|
||||
void Include(const AssetList& assetListToInclude);
|
||||
void Include(const ZoneDefinition& definitionToInclude);
|
||||
|
||||
std::string m_name;
|
||||
GameId m_game;
|
||||
ZoneDefinitionProperties m_properties;
|
||||
std::vector<std::string> m_includes;
|
||||
std::vector<std::string> m_asset_lists;
|
||||
std::vector<std::string> m_ignores;
|
||||
std::vector<std::string> m_targets_to_build;
|
||||
std::vector<std::string> m_gdts;
|
||||
|
@ -2,17 +2,18 @@
|
||||
|
||||
#include "Parsing/Impl/CommentRemovingStreamProxy.h"
|
||||
#include "Parsing/Impl/DefinesStreamProxy.h"
|
||||
#include "Parsing/Impl/IncludingStreamProxy.h"
|
||||
#include "Parsing/Impl/ParserSingleInputStream.h"
|
||||
#include "Parsing/ZoneDefinition/ZoneDefinitionLexer.h"
|
||||
#include "Parsing/ZoneDefinition/ZoneDefinitionParser.h"
|
||||
#include "Zone/Definition/Parsing/ZoneDefinitionLexer.h"
|
||||
#include "Zone/Definition/Parsing/ZoneDefinitionParser.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <format>
|
||||
|
||||
ZoneDefinitionInputStream::ZoneDefinitionInputStream(std::istream& stream, std::string targetName, std::string fileName, const bool verbose)
|
||||
: m_target_name(std::move(targetName)),
|
||||
ZoneDefinitionInputStream::ZoneDefinitionInputStream(std::istream& stream, std::string targetName, std::string fileName, ISearchPath& searchPath)
|
||||
: SearchPathMultiInputStream(searchPath),
|
||||
m_target_name(std::move(targetName)),
|
||||
m_file_name(std::move(fileName)),
|
||||
m_verbose(verbose),
|
||||
m_stream(nullptr),
|
||||
m_previously_set_game(std::nullopt)
|
||||
{
|
||||
@ -23,15 +24,15 @@ ZoneDefinitionInputStream::ZoneDefinitionInputStream(std::istream& stream, std::
|
||||
|
||||
bool ZoneDefinitionInputStream::OpenBaseStream(std::istream& stream)
|
||||
{
|
||||
m_open_streams.emplace_back(std::make_unique<ParserSingleInputStream>(stream, m_file_name));
|
||||
m_open_streams.emplace_back(std::make_unique<ParserMultiInputStream>(stream, m_file_name, *this));
|
||||
return true;
|
||||
}
|
||||
|
||||
void ZoneDefinitionInputStream::SetupStreamProxies()
|
||||
{
|
||||
m_open_streams.emplace_back(std::make_unique<CommentRemovingStreamProxy>(m_open_streams.back().get()));
|
||||
auto definesProxy = std::make_unique<DefinesStreamProxy>(m_open_streams.back().get());
|
||||
m_open_streams.emplace_back(std::move(definesProxy));
|
||||
m_open_streams.emplace_back(std::make_unique<IncludingStreamProxy>(m_open_streams.back().get()));
|
||||
m_open_streams.emplace_back(std::make_unique<DefinesStreamProxy>(m_open_streams.back().get()));
|
||||
|
||||
m_stream = m_open_streams.back().get();
|
||||
}
|
||||
@ -43,11 +44,10 @@ void ZoneDefinitionInputStream::SetPreviouslySetGame(GameId game)
|
||||
|
||||
std::unique_ptr<ZoneDefinition> ZoneDefinitionInputStream::ReadDefinition()
|
||||
{
|
||||
if (m_verbose)
|
||||
std::cout << std::format("Reading zone definition file: {}\n", m_file_name);
|
||||
std::cout << std::format("Reading zone definition file: {}\n", m_file_name);
|
||||
|
||||
const auto lexer = std::make_unique<ZoneDefinitionLexer>(m_stream);
|
||||
const auto parser = std::make_unique<ZoneDefinitionParser>(lexer.get(), m_target_name, m_previously_set_game);
|
||||
const auto parser = std::make_unique<ZoneDefinitionParser>(lexer.get(), m_target_name, m_search_path, *m_stream, m_previously_set_game);
|
||||
|
||||
const auto start = std::chrono::steady_clock::now();
|
||||
std::unique_ptr<ZoneDefinition> definition;
|
||||
@ -55,8 +55,7 @@ std::unique_ptr<ZoneDefinition> ZoneDefinitionInputStream::ReadDefinition()
|
||||
definition = parser->GetParsedValue();
|
||||
const auto end = std::chrono::steady_clock::now();
|
||||
|
||||
if (m_verbose)
|
||||
std::cout << std::format("Processing zone definition took {}ms\n", std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count());
|
||||
std::cout << std::format("Processing zone definition took {}ms\n", std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count());
|
||||
|
||||
return std::move(definition);
|
||||
}
|
||||
|
@ -2,16 +2,18 @@
|
||||
|
||||
#include "Game/IGame.h"
|
||||
#include "Parsing/IParserLineStream.h"
|
||||
#include "SearchPath/ISearchPath.h"
|
||||
#include "SearchPath/SearchPathMultiInputStream.h"
|
||||
#include "ZoneDefinition.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
class ZoneDefinitionInputStream
|
||||
class ZoneDefinitionInputStream : public SearchPathMultiInputStream
|
||||
{
|
||||
public:
|
||||
ZoneDefinitionInputStream(std::istream& stream, std::string targetName, std::string fileName, bool verbose);
|
||||
ZoneDefinitionInputStream(std::istream& stream, std::string targetName, std::string fileName, ISearchPath& searchPath);
|
||||
|
||||
void SetPreviouslySetGame(GameId game);
|
||||
std::unique_ptr<ZoneDefinition> ReadDefinition();
|
||||
@ -22,7 +24,6 @@ private:
|
||||
|
||||
std::string m_target_name;
|
||||
std::string m_file_name;
|
||||
bool m_verbose;
|
||||
IParserLineStream* m_stream;
|
||||
std::vector<std::unique_ptr<IParserLineStream>> m_open_streams;
|
||||
std::optional<GameId> m_previously_set_game;
|
||||
|
Reference in New Issue
Block a user