From 18dc909ec8b1bf6098876a17f2cff9a21479db56 Mon Sep 17 00:00:00 2001 From: MicroTransactionsMatterToo Date: Mon, 1 Apr 2024 10:20:40 +1300 Subject: [PATCH] Half-implemented rework of FgdParser, now doing second pass --- common/src/Assets/PropertyDefinition.cpp | 395 +++------------------ common/src/Assets/PropertyDefinition.h | 300 ++++------------ common/src/IO/FgdParser.cpp | 428 ++++++++++------------- common/src/IO/FgdParser.h | 16 +- 4 files changed, 295 insertions(+), 844 deletions(-) diff --git a/common/src/Assets/PropertyDefinition.cpp b/common/src/Assets/PropertyDefinition.cpp index 937c07f3fd..efa4634e4b 100644 --- a/common/src/Assets/PropertyDefinition.cpp +++ b/common/src/Assets/PropertyDefinition.cpp @@ -4,7 +4,7 @@ This file is part of TrenchBroom. TrenchBroom is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by + it under the terms of the GNU Generals Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. @@ -26,21 +26,24 @@ #include #include +#include namespace TrenchBroom::Assets { PropertyDefinition::PropertyDefinition( std::string key, - const PropertyDefinitionType type, + PropertyTypeVariant type, std::string shortDescription, std::string longDescription, - const bool readOnly) + bool readOnly, + PropertyDefaultValueVariant defaultValue) : m_key{std::move(key)} , m_type{type} , m_shortDescription{std::move(shortDescription)} , m_longDescription{std::move(longDescription)} , m_readOnly{readOnly} + , m_defaultValue{std::move(defaultValue)} { } @@ -51,7 +54,7 @@ const std::string& PropertyDefinition::key() const return m_key; } -PropertyDefinitionType PropertyDefinition::type() const +PropertyTypeVariant PropertyDefinition::type() const { return m_type; } @@ -65,417 +68,101 @@ const std::string& PropertyDefinition::longDescription() const { return m_longDescription; } - -bool PropertyDefinition::readOnly() const -{ - return m_readOnly; -} - -bool PropertyDefinition::equals(const PropertyDefinition* other) const -{ - ensure(other != nullptr, "other is null"); - return type() == other->type() && key() == other->key() && doEquals(other); -} - -bool PropertyDefinition::doEquals(const PropertyDefinition* /* other */) const -{ - return true; -} - -std::string PropertyDefinition::defaultValue(const PropertyDefinition& definition) -{ - switch (definition.type()) - { - case PropertyDefinitionType::StringProperty: { - const auto& stringDef = static_cast(definition); - return stringDef.hasDefaultValue() ? stringDef.defaultValue() : ""; - } - case PropertyDefinitionType::BooleanProperty: { - const auto& boolDef = static_cast(definition); - return boolDef.hasDefaultValue() ? kdl::str_to_string(boolDef.defaultValue()) : ""; - } - case PropertyDefinitionType::IntegerProperty: { - const auto& intDef = static_cast(definition); - return intDef.hasDefaultValue() ? kdl::str_to_string(intDef.defaultValue()) : ""; - } - case PropertyDefinitionType::FloatProperty: { - const auto& floatDef = static_cast(definition); - return floatDef.hasDefaultValue() ? kdl::str_to_string(floatDef.defaultValue()) : ""; - } - case PropertyDefinitionType::ChoiceProperty: { - const auto& choiceDef = static_cast(definition); - return choiceDef.hasDefaultValue() ? kdl::str_to_string(choiceDef.defaultValue()) - : ""; - } - case PropertyDefinitionType::FlagsProperty: { - const auto& flagsDef = static_cast(definition); - return kdl::str_to_string(flagsDef.defaultValue()); - } - case PropertyDefinitionType::TargetSourceProperty: - case PropertyDefinitionType::TargetDestinationProperty: - return ""; - switchDefault(); - } -} - -std::unique_ptr PropertyDefinition::clone( - std::string key, - std::string shortDescription, - std::string longDescription, - bool readOnly) const -{ - return doClone( - std::move(key), std::move(shortDescription), std::move(longDescription), readOnly); -} - -std::unique_ptr PropertyDefinition::doClone( - std::string key, - std::string shortDescription, - std::string longDescription, - bool readOnly) const +const std::optional PropertyDefinition::ioDirection() const { - return std::make_unique( - std::move(key), - type(), - std::move(shortDescription), - std::move(longDescription), - readOnly); + return m_ioDirection; } -StringPropertyDefinition::StringPropertyDefinition( - std::string key, - std::string shortDescription, - std::string longDescription, - const bool readOnly, - std::optional defaultValue) - : PropertyDefinitionWithDefaultValue{ - std::move(key), - PropertyDefinitionType::StringProperty, - std::move(shortDescription), - std::move(longDescription), - readOnly, - std::move(defaultValue)} +bool PropertyDefinition::readOnly() const { + return m_readOnly; } - -std::unique_ptr StringPropertyDefinition::doClone( - std::string key, - std::string shortDescription, - std::string longDescription, - bool readOnly) const +bool PropertyDefinition::isIO() const { - return std::make_unique( - std::move(key), - std::move(shortDescription), - std::move(longDescription), - readOnly, - m_defaultValue); + return m_type.index() == 1; } -BooleanPropertyDefinition::BooleanPropertyDefinition( - std::string key, - std::string shortDescription, - std::string longDescription, - const bool readOnly, - std::optional defaultValue) - : PropertyDefinitionWithDefaultValue{ - std::move(key), - PropertyDefinitionType::BooleanProperty, - std::move(shortDescription), - std::move(longDescription), - readOnly, - std::move(defaultValue)} +PropertyDefaultValueVariant PropertyDefinition::defaultValue() { + return m_defaultValue; } - -std::unique_ptr BooleanPropertyDefinition::doClone( - std::string key, - std::string shortDescription, - std::string longDescription, - bool readOnly) const +void PropertyDefinition::setOptions(std::vector options) { - return std::make_unique( - std::move(key), - std::move(shortDescription), - std::move(longDescription), - readOnly, - m_defaultValue); + m_options = options; } - -IntegerPropertyDefinition::IntegerPropertyDefinition( - std::string key, - std::string shortDescription, - std::string longDescription, - const bool readOnly, - std::optional defaultValue) - : PropertyDefinitionWithDefaultValue{ - std::move(key), - PropertyDefinitionType::IntegerProperty, - std::move(shortDescription), - std::move(longDescription), - readOnly, - std::move(defaultValue)} +void PropertyDefinition::setIODirection(IODirection direction) { + m_ioDirection = direction; } -std::unique_ptr IntegerPropertyDefinition::doClone( - std::string key, - std::string shortDescription, - std::string longDescription, - bool readOnly) const -{ - return std::make_unique( - std::move(key), - std::move(shortDescription), - std::move(longDescription), - readOnly, - m_defaultValue); -} -FloatPropertyDefinition::FloatPropertyDefinition( - std::string key, - std::string shortDescription, - std::string longDescription, - const bool readOnly, - std::optional defaultValue) - : PropertyDefinitionWithDefaultValue{ - std::move(key), - PropertyDefinitionType::FloatProperty, - std::move(shortDescription), - std::move(longDescription), - readOnly, - std::move(defaultValue)} +bool PropertyDefinition::equals(const PropertyDefinition* other) const { + ensure(other != nullptr, "other is null"); + return (type() == other->type() && key() == other->key()); } -std::unique_ptr FloatPropertyDefinition::doClone( +std::unique_ptr PropertyDefinition::clone( std::string key, std::string shortDescription, std::string longDescription, - bool readOnly) const + bool readOnly) { - return std::make_unique( + return std::make_unique( std::move(key), + type(), std::move(shortDescription), std::move(longDescription), readOnly, - m_defaultValue); + defaultValue()); } -ChoicePropertyOption::ChoicePropertyOption(std::string value, std::string description) +ChoiceOption::ChoiceOption(std::string value, std::string description) : m_value{std::move(value)} , m_description{std::move(description)} { } +ChoiceOption::~ChoiceOption() = default; -const std::string& ChoicePropertyOption::value() const +const std::string& ChoiceOption::value() const { return m_value; } -const std::string& ChoicePropertyOption::description() const +const std::string& ChoiceOption::description() const { return m_description; } -kdl_reflect_impl(ChoicePropertyOption); - -ChoicePropertyDefinition::ChoicePropertyDefinition( - std::string key, - std::string shortDescription, - std::string longDescription, - ChoicePropertyOption::List options, - const bool readOnly, - std::optional defaultValue) - : PropertyDefinitionWithDefaultValue{std::move(key), PropertyDefinitionType::ChoiceProperty, std::move(shortDescription), std::move(longDescription), readOnly, std::move(defaultValue)} - , m_options{std::move(options)} -{ -} - -const ChoicePropertyOption::List& ChoicePropertyDefinition::options() const -{ - return m_options; -} - -bool ChoicePropertyDefinition::doEquals(const PropertyDefinition* other) const -{ - return options() == static_cast(other)->options(); -} - -std::unique_ptr ChoicePropertyDefinition::doClone( - std::string key, - std::string shortDescription, - std::string longDescription, - bool readOnly) const -{ - return std::make_unique( - std::move(key), - std::move(shortDescription), - std::move(longDescription), - options(), - readOnly, - m_defaultValue); -} - -FlagsPropertyOption::FlagsPropertyOption( - const int value, - std::string shortDescription, - std::string longDescription, - const bool isDefault) +FlagOption::FlagOption( + int value, std::string shortDescription, std::string longDescription, bool defaultState) : m_value{value} , m_shortDescription{std::move(shortDescription)} , m_longDescription{std::move(longDescription)} - , m_isDefault(isDefault) -{ -} - -int FlagsPropertyOption::value() const + , m_defaultState{defaultState} { - return m_value; } +FlagOption::~FlagOption() = default; -const std::string& FlagsPropertyOption::shortDescription() const +const std::string& FlagOption::shortDescription() const { return m_shortDescription; } -const std::string& FlagsPropertyOption::longDescription() const +const std::string& FlagOption::longDescription() const { return m_longDescription; } -bool FlagsPropertyOption::isDefault() const -{ - return m_isDefault; -} - -kdl_reflect_impl(FlagsPropertyOption); - -FlagsPropertyDefinition::FlagsPropertyDefinition(std::string key) - : PropertyDefinition{ - std::move(key), PropertyDefinitionType::FlagsProperty, "", "", false} +int FlagOption::value() const { + return m_value; } -int FlagsPropertyDefinition::defaultValue() const -{ - int value = 0; - for (const auto& option : m_options) - { - if (option.isDefault()) - { - value = value | option.value(); - } - } - return value; -} - -const FlagsPropertyOption::List& FlagsPropertyDefinition::options() const -{ - return m_options; -} - -const FlagsPropertyOption* FlagsPropertyDefinition::option(const int value) const -{ - for (const auto& option : m_options) - { - if (option.value() == value) - { - return &option; - } - } - return nullptr; -} - -void FlagsPropertyDefinition::addOption( - const int value, - std::string shortDescription, - std::string longDescription, - const bool isDefault) -{ - m_options.emplace_back( - value, std::move(shortDescription), std::move(longDescription), isDefault); -} - -bool FlagsPropertyDefinition::doEquals(const PropertyDefinition* other) const -{ - return options() == static_cast(other)->options(); -} - -std::unique_ptr FlagsPropertyDefinition::doClone( - std::string key, - std::string /* shortDescription */, - std::string /* longDescription */, - bool /* readOnly */) const -{ - auto result = std::make_unique(std::move(key)); - for (const auto& option : options()) - { - result->addOption( - option.value(), - option.shortDescription(), - option.longDescription(), - option.isDefault()); - } - return result; -} - - - IOPropertyDefinition::IOPropertyDefinition( - std::string key, - IOPropertyArgType argumentType, - std::string shortDescription, - std::string longDescription, - IOPropertyDirection ioDirection) - : PropertyDefinition{ - std::move(key), - PropertyDefinitionType::IOProperty, - std::move(shortDescription), - std::move(longDescription), - true} -{ - m_ioDirection = ioDirection; - m_argumentType = argumentType; -} - - -IOPropertyDirection IOPropertyDefinition::ioDirection() const -{ - return m_ioDirection; -} - -IOPropertyArgType IOPropertyDefinition::argumentType() const -{ - return m_argumentType; -} - -UnknownPropertyDefinition::UnknownPropertyDefinition( - std::string key, - std::string shortDescription, - std::string longDescription, - const bool readOnly, - std::optional defaultValue) - : StringPropertyDefinition{ - std::move(key), - std::move(shortDescription), - std::move(longDescription), - readOnly, - std::move(defaultValue)} +bool FlagOption::defaultState() const { + return m_defaultState; } -std::unique_ptr UnknownPropertyDefinition::doClone( - std::string key, - std::string shortDescription, - std::string longDescription, - bool readOnly) const -{ - return std::make_unique( - std::move(key), - std::move(shortDescription), - std::move(longDescription), - readOnly, - m_defaultValue); -} } // namespace TrenchBroom::Assets diff --git a/common/src/Assets/PropertyDefinition.h b/common/src/Assets/PropertyDefinition.h index 86c01dd6e0..e23ccb2974 100644 --- a/common/src/Assets/PropertyDefinition.h +++ b/common/src/Assets/PropertyDefinition.h @@ -26,11 +26,14 @@ #include #include #include -#include #include +#include +#include namespace TrenchBroom::Assets { +class ChoiceOption; +class FlagOption; enum class PropertyDefinitionType { @@ -42,295 +45,120 @@ enum class PropertyDefinitionType FloatProperty, ChoiceProperty, FlagsProperty, - IOProperty + UnknownProperty }; -class PropertyDefinition +enum class IOType { -public: -private: - std::string m_key; - PropertyDefinitionType m_type; - std::string m_shortDescription; - std::string m_longDescription; - bool m_readOnly; - -public: - PropertyDefinition( - std::string key, - PropertyDefinitionType type, - std::string shortDescription, - std::string longDescription, - bool readOnly); - virtual ~PropertyDefinition(); - - const std::string& key() const; - PropertyDefinitionType type() const; - const std::string& shortDescription() const; - const std::string& longDescription() const; - - bool readOnly() const; - - bool equals(const PropertyDefinition* other) const; - - static std::string defaultValue(const PropertyDefinition& definition); - - std::unique_ptr clone( - std::string key, - std::string shortDescription, - std::string longDescription, - bool readOnly) const; - -private: - virtual bool doEquals(const PropertyDefinition* other) const; - virtual std::unique_ptr doClone( - std::string key, - std::string shortDescription, - std::string longDescription, - bool readOnly) const; -}; - -template -class PropertyDefinitionWithDefaultValue : public PropertyDefinition -{ -protected: - std::optional m_defaultValue; - -public: - bool hasDefaultValue() const { return m_defaultValue.has_value(); } - - const T& defaultValue() const - { - ensure(hasDefaultValue(), "property definition has no default value"); - return *m_defaultValue; - } - -protected: - PropertyDefinitionWithDefaultValue( - std::string key, - PropertyDefinitionType type, - std::string shortDescription, - std::string longDescription, - bool readOnly, - std::optional defaultValue = std::nullopt) - : PropertyDefinition(key, type, shortDescription, longDescription, readOnly) - , m_defaultValue(std::move(defaultValue)) - { - } -}; - -class StringPropertyDefinition : public PropertyDefinitionWithDefaultValue -{ -public: - StringPropertyDefinition( - std::string key, - std::string shortDescription, - std::string longDescription, - bool readOnly, - std::optional defaultValue = std::nullopt); - -private: - std::unique_ptr doClone( - std::string key, - std::string shortDescription, - std::string longDescription, - bool readOnly) const override; -}; - -class BooleanPropertyDefinition : public PropertyDefinitionWithDefaultValue -{ -public: - BooleanPropertyDefinition( - std::string key, - std::string shortDescription, - std::string longDescription, - bool readOnly, - std::optional defaultValue = std::nullopt); - -private: - std::unique_ptr doClone( - std::string key, - std::string shortDescription, - std::string longDescription, - bool readOnly) const override; + Void, + Bool, + Float, + Integer, + String, + Unknown }; -class IntegerPropertyDefinition : public PropertyDefinitionWithDefaultValue +enum class IODirection { -public: - IntegerPropertyDefinition( - std::string key, - std::string shortDescription, - std::string longDescription, - bool readOnly, - std::optional defaultValue = std::nullopt); - -private: - std::unique_ptr doClone( - std::string key, - std::string shortDescription, - std::string longDescription, - bool readOnly) const override; + Input, + Output }; -class FloatPropertyDefinition : public PropertyDefinitionWithDefaultValue -{ -public: - FloatPropertyDefinition( - std::string key, - std::string shortDescription, - std::string longDescription, - bool readOnly, - std::optional defaultValue = std::nullopt); +using PropertyTypeVariant = std::variant; +using PropertyDefaultValueVariant = + std::variant; +using PropertyOptionVariant = std::variant; -private: - std::unique_ptr doClone( - std::string key, - std::string shortDescription, - std::string longDescription, - bool readOnly) const override; -}; -class ChoicePropertyOption +class ChoiceOption { public: - using List = std::vector; + using List = std::vector; private: std::string m_value; std::string m_description; public: - ChoicePropertyOption(std::string value, std::string description); + ChoiceOption(std::string value, std::string description); + ~ChoiceOption(); const std::string& value() const; const std::string& description() const; - kdl_reflect_decl(ChoicePropertyOption, m_value, m_description); -}; - -class ChoicePropertyDefinition : public PropertyDefinitionWithDefaultValue -{ -private: - ChoicePropertyOption::List m_options; - -public: - ChoicePropertyDefinition( - std::string key, - std::string shortDescription, - std::string longDescription, - ChoicePropertyOption::List options, - bool readOnly, - std::optional defaultValue = std::nullopt); - const ChoicePropertyOption::List& options() const; - -private: - bool doEquals(const PropertyDefinition* other) const override; - std::unique_ptr doClone( - std::string key, - std::string shortDescription, - std::string longDescription, - bool readOnly) const override; + kdl_reflect_decl(ChoiceOption, m_value, m_description); }; -class FlagsPropertyOption +class FlagOption { public: - using List = std::vector; + using List = std::vector; private: int m_value; std::string m_shortDescription; std::string m_longDescription; - bool m_isDefault; + bool m_defaultState; public: - FlagsPropertyOption( - int value, std::string shortDescription, std::string longDescription, bool isDefault); + FlagOption( + int value, + std::string shortDescription, + std::string longDescription, + bool defaultState); + ~FlagOption(); + int value() const; const std::string& shortDescription() const; const std::string& longDescription() const; - bool isDefault() const; + bool defaultState() const; - kdl_reflect_decl( - FlagsPropertyOption, m_shortDescription, m_longDescription, m_isDefault); + kdl_reflect_decl(FlagOption, m_shortDescription, m_longDescription, m_defaultState); }; -class FlagsPropertyDefinition : public PropertyDefinition +class PropertyDefinition { private: - FlagsPropertyOption::List m_options; - -public: - explicit FlagsPropertyDefinition(std::string key); + std::string m_key; + PropertyTypeVariant m_type; + std::string m_shortDescription; + std::string m_longDescription; + bool m_readOnly; + PropertyDefaultValueVariant m_defaultValue = std::monostate{}; + std::optional m_ioDirection; - int defaultValue() const; - const FlagsPropertyOption::List& options() const; - const FlagsPropertyOption* option(int value) const; - void addOption( - int value, std::string shortDescription, std::string longDescription, bool isDefault); + std::vector m_options; -private: - bool doEquals(const PropertyDefinition* other) const override; - std::unique_ptr doClone( +public: + PropertyDefinition( std::string key, + PropertyTypeVariant type, std::string shortDescription, std::string longDescription, - bool readOnly) const override; -}; - + bool readOnly, + PropertyDefaultValueVariant defaultValue); + virtual ~PropertyDefinition(); -enum class IOPropertyDirection -{ - Input, - Output -}; + const std::string& key() const; + PropertyTypeVariant type() const; + const std::string& shortDescription() const; + const std::string& longDescription() const; + const std::optional ioDirection() const; -enum class IOPropertyArgType -{ - Void, - Integer, - Float, - String, - Bool, - Unknown -}; + bool readOnly() const; + bool isIO() const; + PropertyDefaultValueVariant defaultValue(); + void setOptions(std::vector options); + void setIODirection(IODirection direction); -class IOPropertyDefinition : public PropertyDefinition -{ -private: - IOPropertyDirection m_ioDirection; - IOPropertyArgType m_argumentType; + bool equals(const PropertyDefinition* other) const; -public: - IOPropertyDefinition( + std::unique_ptr clone( std::string key, - IOPropertyArgType argumentType, std::string shortDescription, std::string longDescription, - IOPropertyDirection ioDirection - ); - - IOPropertyDirection ioDirection() const; - IOPropertyArgType argumentType() const; + bool readOnly); }; -class UnknownPropertyDefinition : public StringPropertyDefinition -{ -public: - UnknownPropertyDefinition( - std::string key, - std::string shortDescription, - std::string longDescription, - bool readOnly, - std::optional defaultValue = std::nullopt); - -private: - std::unique_ptr doClone( - std::string key, - std::string shortDescription, - std::string longDescription, - bool readOnly) const override; -}; } // namespace TrenchBroom::Assets diff --git a/common/src/IO/FgdParser.cpp b/common/src/IO/FgdParser.cpp index 82351cf8c9..b5825b3d86 100644 --- a/common/src/IO/FgdParser.cpp +++ b/common/src/IO/FgdParser.cpp @@ -193,6 +193,35 @@ FgdParser::TokenNameMap FgdParser::tokenNames() const }; } + +PropertyTypeMap FgdParser::propertyTypeNames() +{ + using PropDefType = Assets::PropertyDefinitionType; + + return { + {"target_source", PropDefType::TargetSourceProperty}, + {"target_destination", PropDefType::TargetDestinationProperty}, + {"string", PropDefType::StringProperty}, + {"boolean", PropDefType::BooleanProperty}, + {"integer", PropDefType::IntegerProperty}, + {"float", PropDefType::FloatProperty}, + {"flags", PropDefType::FlagsProperty}, + {"choices", PropDefType::ChoiceProperty}}; +} + +IOTypeMap FgdParser::ioTypeNames() +{ + using IOType = Assets::IOType; + + return { + {"void", IOType::Void}, + {"bool", IOType::Bool}, + {"float", IOType::Float}, + {"string", IOType::String}, + {"integer", IOType::Integer}}; +} + + class FgdParser::PushIncludePath { private: @@ -608,191 +637,142 @@ std::vector> FgdParser:: while (token.type() != FgdToken::CBracket) { - const auto propertyKey = token.data(); - const auto line = token.line(); - const auto column = token.column(); - - std::unique_ptr propertyDefinition; - if ((propertyKey == "input" || propertyKey == "output") && - m_tokenizer.peekToken().type() == FgdToken::Word - ) - { - propertyDefinition = parseIOPropertyDefinition(status, propertyKey); - } - else - { - expect(status, FgdToken::OParenthesis, m_tokenizer.nextToken()); - token = expect(status, FgdToken::Word, m_tokenizer.nextToken()); - const auto typeName = token.data(); - expect(status, FgdToken::CParenthesis, m_tokenizer.nextToken()); - - propertyDefinition = - parsePropertyDefinition(status, propertyKey, typeName, line, column); - } - - if (!addPropertyDefinition(propertyDefinitions, std::move(propertyDefinition))) - { - status.warn( - line, - column, - fmt::format("Skipping duplicate property definition: '{}'", propertyKey)); - } - - token = expect(status, FgdToken::Word | FgdToken::CBracket, m_tokenizer.nextToken()); + parsePropertyDefinition(status); } return propertyDefinitions; } +Assets::PropertyDefinitionType FgdParser::getPropertyType(ParserStatus& status) +{ + auto token = expect(status, FgdToken::Word, m_tokenizer.nextToken()); + const auto typeName = token.data(); + const auto propTypeMap = propertyTypeNames(); + auto it = propTypeMap.find(typeName); + const auto propertyType = + (it == propTypeMap.end()) ? PropDefType::UnknownProperty : it->second; + + return propertyType; +} std::unique_ptr FgdParser::parsePropertyDefinition( - ParserStatus& status, - std::string propertyKey, - const std::string& typeName, - const size_t line, - const size_t column) + ParserStatus& status) { - if (kdl::ci::str_is_equal(typeName, "target_source")) - { - return parseTargetSourcePropertyDefinition(status, std::move(propertyKey)); - } - if (kdl::ci::str_is_equal(typeName, "target_destination")) - { - return parseTargetDestinationPropertyDefinition(status, std::move(propertyKey)); - } - if (kdl::ci::str_is_equal(typeName, "string")) + + + auto token = expect(status, FgdToken::Word, m_tokenizer.peekToken()); + const auto line = token.line(); + const auto column = token.column(); + + const auto propertyKey = token.data(); + + + expect(status, FgdToken::OParenthesis, m_tokenizer.nextToken()); + const auto propertyType = getPropertyType(status); + expect(status, FgdToken::CParenthesis, m_tokenizer.nextToken()); + + switch (propertyType) { - return parseStringPropertyDefinition(status, std::move(propertyKey)); + case PropDefType::BooleanProperty: + case PropDefType::FloatProperty: + case PropDefType::IntegerProperty: + case PropDefType::StringProperty: + case PropDefType::UnknownProperty: { + const auto readOnly = parseReadOnlyFlag(status); + auto shortDescription = parsePropertyDescription(status); + auto defaultValue = parseDefaultValue(status, propertyType); + auto longDescription = parsePropertyDescription(status); + return std::make_unique( + propertyKey, + propertyType, + shortDescription, + longDescription, + readOnly, + defaultValue); + break; } - if (kdl::ci::str_is_equal(typeName, "integer")) - { - return parseIntegerPropertyDefinition(status, std::move(propertyKey)); + case PropDefType::TargetDestinationProperty: + case PropDefType::TargetSourceProperty: { + const auto readOnly = parseReadOnlyFlag(status); + auto shortDescription = parsePropertyDescription(status); + parseDefaultValue(status, propertyType); + auto longDescription = parsePropertyDescription(status); + return std::make_unique( + propertyKey, + propertyType, + shortDescription, + longDescription, + readOnly, + std::monostate{}); + break; } - if (kdl::ci::str_is_equal(typeName, "float")) - { - return parseFloatPropertyDefinition(status, std::move(propertyKey)); + case PropDefType::ChoiceProperty: + return parseChoicesPropertyDefinition(status, propertyKey); + case PropDefType::FlagsProperty: + return parseFlagsPropertyDefinition(status, propertyKey); } - if (kdl::ci::str_is_equal(typeName, "choices")) +} + +Assets::PropertyDefaultValueVariant FgdParser::parseDefaultValue( + ParserStatus& status, Assets::PropertyDefinitionType propertyType) +{ + auto token = m_tokenizer.peekToken(); + if (token.type() != FgdToken::Colon) { - return parseChoicesPropertyDefinition(status, std::move(propertyKey)); + return Assets::PropertyDefaultValueVariant{}; } - if (kdl::ci::str_is_equal(typeName, "flags")) + + m_tokenizer.nextToken(); + switch (propertyType) { - return parseFlagsPropertyDefinition(status, std::move(propertyKey)); + case PropDefType::BooleanProperty: + return static_cast(parseDefaultIntegerValue(status).value_or(false)); + case PropDefType::IntegerProperty: + return parseDefaultIntegerValue(status).value_or(std::monostate{}); + case PropDefType::FloatProperty: + return parseDefaultFloatValue(status).value_or(std::monostate{}); + case PropDefType::StringProperty: + case PropDefType::TargetDestinationProperty: + case PropDefType::TargetSourceProperty: + case PropDefType::UnknownProperty: + return parseDefaultStringValue(status).value_or(std::monostate{}); + case PropDefType::ChoiceProperty: + return parseDefaultChoiceValue(status).value_or(std::monostate{}); + default: + return std::monostate{}; } - - status.debug( - line, - column, - fmt::format( - "Unknown property definition type '{}' for property '{}'", typeName, propertyKey)); - return parseUnknownPropertyDefinition(status, std::move(propertyKey)); } std::unique_ptr FgdParser::parseIOPropertyDefinition( - ParserStatus& status, std::string propertyKey) + ParserStatus& status, std::string ioDirection) { auto token = expect(status, FgdToken::Word, m_tokenizer.nextToken()); + const auto ioTypeMap = IOTypeMap(); const auto ioKey = token.data(); expect(status, FgdToken::OParenthesis, m_tokenizer.nextToken()); - const auto argType = parseIOType(status); + token = expect(status, FgdToken::Word, m_tokenizer.nextToken()); + const auto typeName = token.data(); + auto it = ioTypeMap.find(typeName); + const auto ioType = (it == ioTypeMap.end()) ? Assets::IOType::Unknown : it->second; + expect(status, FgdToken::CParenthesis, m_tokenizer.nextToken()); const auto shortDescription = parsePropertyDescription(status); - const auto direction = (propertyKey == "input") ? Assets::IOPropertyDirection::Input : Assets::IOPropertyDirection::Output; - - - return std::make_unique( - ioKey, - argType, - shortDescription, - shortDescription, - direction - ); -} - -std::unique_ptr FgdParser:: - parseTargetSourcePropertyDefinition(ParserStatus& status, std::string propertyKey) -{ - const auto readOnly = parseReadOnlyFlag(status); - auto shortDescription = parsePropertyDescription(status); - parseDefaultStringValue(status); - auto longDescription = parsePropertyDescription(status); - return std::make_unique( - std::move(propertyKey), - Assets::PropertyDefinitionType::TargetSourceProperty, - std::move(shortDescription), - std::move(longDescription), - readOnly); -} + const auto longDescripton = ""; + const auto propertyDefinition = Assets::PropertyDefinition{ + ioKey, ioType, shortDescription, longDescripton, false, std::monostate{}}; -std::unique_ptr FgdParser:: - parseTargetDestinationPropertyDefinition(ParserStatus& status, std::string propertyKey) -{ - const auto readOnly = parseReadOnlyFlag(status); - auto shortDescription = parsePropertyDescription(status); - parseDefaultStringValue(status); - auto longDescription = parsePropertyDescription(status); - return std::make_unique( - std::move(propertyKey), - Assets::PropertyDefinitionType::TargetDestinationProperty, - std::move(shortDescription), - std::move(longDescription), - readOnly); + return std::make_unique(propertyDefinition); } -std::unique_ptr FgdParser::parseStringPropertyDefinition( - ParserStatus& status, std::string propertyKey) -{ - const auto readOnly = parseReadOnlyFlag(status); - auto shortDescription = parsePropertyDescription(status); - auto defaultValue = parseDefaultStringValue(status); - auto longDescription = parsePropertyDescription(status); - return std::make_unique( - std::move(propertyKey), - std::move(shortDescription), - std::move(longDescription), - readOnly, - std::move(defaultValue)); -} - -std::unique_ptr FgdParser::parseIntegerPropertyDefinition( - ParserStatus& status, std::string propertyKey) -{ - const auto readOnly = parseReadOnlyFlag(status); - auto shortDescription = parsePropertyDescription(status); - auto defaultValue = parseDefaultIntegerValue(status); - auto longDescription = parsePropertyDescription(status); - return std::make_unique( - std::move(propertyKey), - std::move(shortDescription), - std::move(longDescription), - readOnly, - std::move(defaultValue)); -} - -std::unique_ptr FgdParser::parseFloatPropertyDefinition( - ParserStatus& status, std::string propertyKey) -{ - const auto readOnly = parseReadOnlyFlag(status); - auto shortDescription = parsePropertyDescription(status); - auto defaultValue = parseDefaultFloatValue(status); - auto longDescription = parsePropertyDescription(status); - return std::make_unique( - std::move(propertyKey), - std::move(shortDescription), - std::move(longDescription), - readOnly, - std::move(defaultValue)); -} std::unique_ptr FgdParser::parseChoicesPropertyDefinition( ParserStatus& status, std::string propertyKey) { const auto readOnly = parseReadOnlyFlag(status); auto shortDescription = parsePropertyDescription(status); - auto defaultValue = parseDefaultChoiceValue(status); + auto defaultValue = parseDefaultChoiceValue(status).value_or(std::monostate{}); auto longDescription = parsePropertyDescription(status); expect(status, FgdToken::Equality, m_tokenizer.nextToken()); @@ -803,7 +783,7 @@ std::unique_ptr FgdParser::parseChoicesPropertyDefin FgdToken::Integer | FgdToken::Decimal | FgdToken::String | FgdToken::CBracket, m_tokenizer.nextToken()); - auto options = Assets::ChoicePropertyOption::List{}; + auto options = Assets::ChoiceOption::List{}; while (token.type() != FgdToken::CBracket) { auto value = token.data(); @@ -817,11 +797,11 @@ std::unique_ptr FgdParser::parseChoicesPropertyDefin m_tokenizer.nextToken()); } - return std::make_unique( + return std::make_unique( std::move(propertyKey), + PropDefType::ChoiceProperty, std::move(shortDescription), std::move(longDescription), - std::move(options), readOnly, std::move(defaultValue)); } @@ -838,8 +818,9 @@ std::unique_ptr FgdParser::parseFlagsPropertyDefinit auto token = expect(status, FgdToken::Integer | FgdToken::CBracket, m_tokenizer.nextToken()); - auto definition = - std::make_unique(std::move(propertyKey)); + auto definition = std::make_unique( + propertyKey, PropDefType::FlagsProperty, "", "", false, std::monostate{}); + auto options = Assets::FlagOption::List{}; while (token.type() != FgdToken::CBracket) { @@ -872,27 +853,14 @@ std::unique_ptr FgdParser::parseFlagsPropertyDefinit expect(status, FgdToken::Integer | FgdToken::CBracket, m_tokenizer.nextToken()); } - definition->addOption( - value, std::move(shortDescription), std::move(longDescription), defaultValue); + auto option = + Assets::FlagOption{value, shortDescription, longDescription, defaultValue}; + options.push_back(std::move(option)); } + definition->setOptions(std::move(options)); return definition; } -std::unique_ptr FgdParser::parseUnknownPropertyDefinition( - ParserStatus& status, std::string propertyKey) -{ - const auto readOnly = parseReadOnlyFlag(status); - auto shortDescription = parsePropertyDescription(status); - auto defaultValue = parseDefaultStringValue(status); - auto longDescription = parsePropertyDescription(status); - return std::make_unique( - std::move(propertyKey), - std::move(shortDescription), - std::move(longDescription), - readOnly, - std::move(defaultValue)); -} - bool FgdParser::parseReadOnlyFlag(ParserStatus& /* status */) { auto token = m_tokenizer.peekToken(); @@ -921,79 +889,64 @@ std::string FgdParser::parsePropertyDescription(ParserStatus& status) std::optional FgdParser::parseDefaultStringValue(ParserStatus& status) { - auto token = m_tokenizer.peekToken(); - if (token.type() == FgdToken::Colon) + auto token = expect( + status, + FgdToken::String | FgdToken::Colon | FgdToken::Integer | FgdToken::Decimal, + m_tokenizer.peekToken()); + if (token.type() == FgdToken::String) { - m_tokenizer.nextToken(); - token = expect( - status, - FgdToken::String | FgdToken::Colon | FgdToken::Integer | FgdToken::Decimal, - m_tokenizer.peekToken()); - if (token.type() == FgdToken::String) - { - token = m_tokenizer.nextToken(); - return token.data(); - } - if (token.type() == FgdToken::Integer || token.type() == FgdToken::Decimal) - { - token = m_tokenizer.nextToken(); - status.warn( - token.line(), token.column(), "Found numeric default value for string property"); - return token.data(); - } + token = m_tokenizer.nextToken(); + return token.data(); + } + if (token.type() == FgdToken::Integer || token.type() == FgdToken::Decimal) + { + token = m_tokenizer.nextToken(); + status.warn( + token.line(), token.column(), "Found numeric default value for string property"); + return token.data(); } return std::nullopt; } std::optional FgdParser::parseDefaultIntegerValue(ParserStatus& status) { - auto token = m_tokenizer.peekToken(); - if (token.type() == FgdToken::Colon) + auto token = expect( + status, + FgdToken::Integer | FgdToken::Decimal | FgdToken::Colon, + m_tokenizer.peekToken()); + if (token.type() == FgdToken::Integer) { - m_tokenizer.nextToken(); - token = expect( - status, - FgdToken::Integer | FgdToken::Decimal | FgdToken::Colon, - m_tokenizer.peekToken()); - if (token.type() == FgdToken::Integer) - { - token = m_tokenizer.nextToken(); - return token.toInteger(); - } - if (token.type() == FgdToken::Decimal) - { // be graceful for DaZ - token = m_tokenizer.nextToken(); - status.warn( - token.line(), token.column(), "Found float default value for integer property"); - return static_cast(token.toFloat()); - } + token = m_tokenizer.nextToken(); + return token.toInteger(); + } + if (token.type() == FgdToken::Decimal) + { // be graceful for DaZ + token = m_tokenizer.nextToken(); + status.warn( + token.line(), token.column(), "Found float default value for integer property"); + return static_cast(token.toFloat()); } return std::nullopt; } std::optional FgdParser::parseDefaultFloatValue(ParserStatus& status) { - auto token = m_tokenizer.peekToken(); - if (token.type() == FgdToken::Colon) + // the default value should have quotes around it, but sometimes they're missing + auto token = expect( + status, + FgdToken::String | FgdToken::Decimal | FgdToken::Integer | FgdToken::Colon, + m_tokenizer.peekToken()); + if (token.type() != FgdToken::Colon) { - m_tokenizer.nextToken(); - // the default value should have quotes around it, but sometimes they're missing - token = expect( - status, - FgdToken::String | FgdToken::Decimal | FgdToken::Integer | FgdToken::Colon, - m_tokenizer.peekToken()); - if (token.type() != FgdToken::Colon) + token = m_tokenizer.nextToken(); + if (token.type() != FgdToken::String) { - token = m_tokenizer.nextToken(); - if (token.type() != FgdToken::String) - { - status.warn( - token.line(), - token.column(), - fmt::format("Unquoted float default value {}", token.data())); - } - return token.toFloat(); + status.warn( + token.line(), + token.column(), + fmt::format("Unquoted float default value {}", token.data())); } + return token.toFloat(); } return std::nullopt; } @@ -1091,27 +1044,6 @@ std::string FgdParser::parseString(ParserStatus& status) } } -Assets::IOPropertyArgType FgdParser::parseIOType(ParserStatus& status) -{ - auto token = expect(status, FgdToken::Word, m_tokenizer.nextToken()); - const auto line = token.line(); - const auto column = token.column(); - const auto typeString = token.data(); - - - if (typeString == "void") { return Assets::IOPropertyArgType::Void; } - if (typeString == "float") { return Assets::IOPropertyArgType::Float; } - if (typeString == "integer") { return Assets::IOPropertyArgType::Integer; } - if (typeString == "string") { return Assets::IOPropertyArgType::String; } - if (typeString == "bool") { return Assets::IOPropertyArgType::Bool; } - - status.warn( - line, - column, - fmt::format("Unknown IO argument type {}", typeString)); - return Assets::IOPropertyArgType::Unknown; -} - std::vector FgdParser::parseInclude(ParserStatus& status) { auto token = expect(status, FgdToken::Word, m_tokenizer.nextToken()); diff --git a/common/src/IO/FgdParser.h b/common/src/IO/FgdParser.h index 686d8bcf83..ba78fa3e74 100644 --- a/common/src/IO/FgdParser.h +++ b/common/src/IO/FgdParser.h @@ -46,6 +46,10 @@ enum class EntityDefinitionClassType; class FileSystem; class ParserStatus; +using PropertyTypeMap = std::unordered_map; +using IOTypeMap = std::unordered_map; +using PropDefType = Assets::PropertyDefinitionType; + namespace FgdToken { using Type = unsigned int; @@ -103,6 +107,8 @@ class FgdParser : public EntityDefinitionParser, public Parser private: TokenNameMap tokenNames() const override; + static PropertyTypeMap propertyTypeNames(); + static IOTypeMap ioTypeNames(); std::vector parseClassInfos(ParserStatus& status) override; @@ -125,12 +131,11 @@ class FgdParser : public EntityDefinitionParser, public Parser std::vector> parsePropertyDefinitions( ParserStatus& status); + Assets::PropertyDefinitionType getPropertyType(ParserStatus& status); std::unique_ptr parsePropertyDefinition( - ParserStatus& status, - std::string propertyKey, - const std::string& typeName, - size_t line, - size_t column); + ParserStatus& status); + Assets::PropertyDefaultValueVariant parseDefaultValue( + ParserStatus& status, Assets::PropertyDefinitionType propertyType); std::unique_ptr parseIOPropertyDefinition( ParserStatus& status, std::string propertyKey); std::unique_ptr parseTargetSourcePropertyDefinition( @@ -161,7 +166,6 @@ class FgdParser : public EntityDefinitionParser, public Parser vm::bbox3 parseSize(ParserStatus& status); Color parseColor(ParserStatus& status); std::string parseString(ParserStatus& status); - Assets::IOPropertyArgType parseIOType(ParserStatus& status); std::vector parseInclude(ParserStatus& status); std::vector handleInclude(