diff --git a/src/spider/CMakeLists.txt b/src/spider/CMakeLists.txt index 98bcc7b1c..fd1f92859 100644 --- a/src/spider/CMakeLists.txt +++ b/src/spider/CMakeLists.txt @@ -198,6 +198,7 @@ add_library(spider::spider ALIAS spider_client) set(SPIDER_TDL_SHARED_SOURCES tdl/parser/ast/Node.cpp tdl/parser/ast/node_impl/Identifier.cpp + tdl/parser/ast/node_impl/NamedVar.cpp tdl/parser/ast/node_impl/type_impl/container_impl/List.cpp tdl/parser/ast/node_impl/type_impl/container_impl/Map.cpp tdl/parser/ast/node_impl/type_impl/primitive_impl/Bool.cpp @@ -213,6 +214,7 @@ set(SPIDER_TDL_SHARED_HEADERS tdl/parser/ast/FloatSpec.hpp tdl/parser/ast/IntSpec.hpp tdl/parser/ast/node_impl/Identifier.hpp + tdl/parser/ast/node_impl/NamedVar.hpp tdl/parser/ast/node_impl/Type.hpp tdl/parser/ast/node_impl/type_impl/Container.hpp tdl/parser/ast/node_impl/type_impl/container_impl/List.hpp diff --git a/src/spider/tdl/parser/ast/node_impl/Identifier.cpp b/src/spider/tdl/parser/ast/node_impl/Identifier.cpp index 8d58a7eb1..b3e4ad9cd 100644 --- a/src/spider/tdl/parser/ast/node_impl/Identifier.cpp +++ b/src/spider/tdl/parser/ast/node_impl/Identifier.cpp @@ -11,6 +11,6 @@ namespace spider::tdl::parser::ast::node_impl { auto Identifier::serialize_to_str(size_t indentation_level) const -> ystdlib::error_handling::Result { - return fmt::format("{}[Identifier]: {}", create_indentation(indentation_level), m_name); + return fmt::format("{}[Identifier]:{}", create_indentation(indentation_level), m_name); } } // namespace spider::tdl::parser::ast::node_impl diff --git a/src/spider/tdl/parser/ast/node_impl/NamedVar.cpp b/src/spider/tdl/parser/ast/node_impl/NamedVar.cpp new file mode 100644 index 000000000..c988b0f14 --- /dev/null +++ b/src/spider/tdl/parser/ast/node_impl/NamedVar.cpp @@ -0,0 +1,39 @@ +#include "NamedVar.hpp" + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +namespace spider::tdl::parser::ast::node_impl { +auto NamedVar::create(std::unique_ptr id, std::unique_ptr type) + -> ystdlib::error_handling::Result> { + YSTDLIB_ERROR_HANDLING_TRYV(validate_child_node_type(id.get())); + YSTDLIB_ERROR_HANDLING_TRYV(validate_child_node_type(type.get())); + + auto named_var{std::make_unique(NamedVar{})}; + YSTDLIB_ERROR_HANDLING_TRYV(named_var->add_child(std::move(id))); + YSTDLIB_ERROR_HANDLING_TRYV(named_var->add_child(std::move(type))); + return named_var; +} + +auto NamedVar::serialize_to_str(size_t indentation_level) const + -> ystdlib::error_handling::Result { + return fmt::format( + "{}[NamedVar]:\n{}Id:\n{}\n{}Type:\n{}", + create_indentation(indentation_level), + create_indentation(indentation_level + 1), + YSTDLIB_ERROR_HANDLING_TRYX(get_id()->serialize_to_str(indentation_level + 2)), + create_indentation(indentation_level + 1), + YSTDLIB_ERROR_HANDLING_TRYX(get_type()->serialize_to_str(indentation_level + 2)) + ); +} +} // namespace spider::tdl::parser::ast::node_impl diff --git a/src/spider/tdl/parser/ast/node_impl/NamedVar.hpp b/src/spider/tdl/parser/ast/node_impl/NamedVar.hpp new file mode 100644 index 000000000..deed577a2 --- /dev/null +++ b/src/spider/tdl/parser/ast/node_impl/NamedVar.hpp @@ -0,0 +1,54 @@ +#ifndef SPIDER_TDL_PARSER_AST_NODE_IMPL_NAMEDVAR_HPP +#define SPIDER_TDL_PARSER_AST_NODE_IMPL_NAMEDVAR_HPP + +#include +#include +#include + +#include + +#include +#include +#include + +namespace spider::tdl::parser::ast::node_impl { +/** + * Represents a named variable in the AST. A named variable contains an identifier and a type. + */ +class NamedVar : public Node { +public: + // Factory function + /** + * @param id + * @param type + * @return A result containing a unique pointer to a new `NamedVar` instance with the given name + * on success, or an error code indicating the failure: + * - Forwards `validate_child_node_type`'s return values. + */ + [[nodiscard]] static auto create(std::unique_ptr id, std::unique_ptr type) + -> ystdlib::error_handling::Result>; + + // Methods implementing `Node` + [[nodiscard]] auto serialize_to_str(size_t indentation_level) const + -> ystdlib::error_handling::Result override; + + // Methods + [[nodiscard]] auto get_id() const noexcept -> Identifier const* { + // The factory function ensures that the first child is of type `Identifier`. + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-static-cast-downcast) + return static_cast(get_child_unsafe(0)); + } + + [[nodiscard]] auto get_type() const noexcept -> Type const* { + // The factory function ensures that the second child is of type `Type`. + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-static-cast-downcast) + return static_cast(get_child_unsafe(1)); + } + +private: + // Constructor + NamedVar() = default; +}; +} // namespace spider::tdl::parser::ast::node_impl + +#endif // SPIDER_TDL_PARSER_AST_NODE_IMPL_NAMEDVAR_HPP diff --git a/tests/tdl/test-parser-ast.cpp b/tests/tdl/test-parser-ast.cpp index d949676e2..94df70457 100644 --- a/tests/tdl/test-parser-ast.cpp +++ b/tests/tdl/test-parser-ast.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -24,6 +25,7 @@ TEST_CASE("test-ast-node", "[tdl][ast][Node]") { using spider::tdl::parser::ast::IntSpec; using spider::tdl::parser::ast::Node; using spider::tdl::parser::ast::node_impl::Identifier; + using spider::tdl::parser::ast::node_impl::NamedVar; using spider::tdl::parser::ast::node_impl::type_impl::container_impl::List; using spider::tdl::parser::ast::node_impl::type_impl::container_impl::Map; using spider::tdl::parser::ast::node_impl::type_impl::primitive_impl::Bool; @@ -33,7 +35,7 @@ TEST_CASE("test-ast-node", "[tdl][ast][Node]") { SECTION("Identifier") { constexpr std::string_view cTestName{"test_name"}; - constexpr std::string_view cSerializedIdentifier{"[Identifier]: test_name"}; + constexpr std::string_view cSerializedIdentifier{"[Identifier]:test_name"}; auto const node{Identifier::create(std::string{cTestName})}; auto const* identifier{dynamic_cast(node.get())}; @@ -200,6 +202,35 @@ TEST_CASE("test-ast-node", "[tdl][ast][Node]") { REQUIRE(unsupported_list_key_type_map_result.error() == Map::ErrorCode{Map::ErrorCodeEnum::UnsupportedKeyType}); } + + SECTION("NamedVar") { + auto id_result{Identifier::create("TestId")}; + auto map_result{Map::create(Int::create(IntSpec::Int64), Float::create(FloatSpec::Double))}; + REQUIRE_FALSE(map_result.has_error()); + auto named_var_result{ + NamedVar::create(std::move(id_result), std::move(map_result.value())) + }; + REQUIRE_FALSE(named_var_result.has_error()); + auto const* named_var_node{dynamic_cast(named_var_result.value().get())}; + REQUIRE(nullptr != named_var_node); + + REQUIRE(named_var_node->get_num_children() == 2); + + constexpr std::string_view cExpectedSerializedResult{ + "[NamedVar]:\n" + " Id:\n" + " [Identifier]:TestId\n" + " Type:\n" + " [Type[Container[Map]]]:\n" + " KeyType:\n" + " [Type[Primitive[Int]]]:int64\n" + " ValueType:\n" + " [Type[Primitive[Float]]]:double" + }; + auto const serialized_result{named_var_node->serialize_to_str(0)}; + REQUIRE_FALSE(serialized_result.has_error()); + REQUIRE(serialized_result.value() == cExpectedSerializedResult); + } } } // namespace