From fe0650f56da149471c10e39f64c7fdb4e0c4e048 Mon Sep 17 00:00:00 2001 From: LinZhihao-723 Date: Thu, 7 Aug 2025 10:28:51 -0400 Subject: [PATCH 01/24] Add ast base implementation. --- src/spider/tdl/parser/ast/Node.cpp | 32 +++++++++++- src/spider/tdl/parser/ast/Node.hpp | 84 +++++++++++++++++++++++++++++- 2 files changed, 113 insertions(+), 3 deletions(-) diff --git a/src/spider/tdl/parser/ast/Node.cpp b/src/spider/tdl/parser/ast/Node.cpp index 1dbe97ad0..caad6a425 100644 --- a/src/spider/tdl/parser/ast/Node.cpp +++ b/src/spider/tdl/parser/ast/Node.cpp @@ -1,8 +1,12 @@ #include "Node.hpp" +#include +#include #include +#include #include +#include using spider::tdl::parser::ast::Node; using NodeErrorCodeCategory = ystdlib::error_handling::ErrorCategory; @@ -15,9 +19,33 @@ auto NodeErrorCodeCategory::name() const noexcept -> char const* { template <> auto NodeErrorCodeCategory ::message(Node::ErrorCodeEnum error_enum) const -> std::string { switch (error_enum) { - case Node::ErrorCodeEnum::PlaceholderError: - return "This is a placeholder error code enum"; + case Node::ErrorCodeEnum::ChildIdOutOfBounds: + return "The child ID is out of bounds."; + case Node::ErrorCodeEnum::ParentAlreadySet: + return "The AST node's parent has already been set."; default: return "Unknown error code enum"; } } + +namespace spider::tdl::parser::ast { +namespace { +using ystdlib::error_handling::Result; +} // namespace + +auto Node::get_child(size_t child_id) const -> Result { + if (m_children.size() <= child_id) { + return Node::ErrorCode{Node::ErrorCodeEnum::ChildIdOutOfBounds}; + } + return get_child_unsafe(child_id); +} + +auto Node::add_child(std::unique_ptr child) -> Result { + if (nullptr != child->get_parent()) { + return Node::ErrorCode{Node::ErrorCodeEnum::ParentAlreadySet}; + } + child->m_parent = this; + m_children.emplace_back(std::move(child)); + return ystdlib::error_handling::success(); +} +} // namespace spider::tdl::parser::ast diff --git a/src/spider/tdl/parser/ast/Node.hpp b/src/spider/tdl/parser/ast/Node.hpp index 33af7f890..faa6dd765 100644 --- a/src/spider/tdl/parser/ast/Node.hpp +++ b/src/spider/tdl/parser/ast/Node.hpp @@ -1,9 +1,13 @@ #ifndef SPIDER_TDL_PARSER_AST_NODE_HPP #define SPIDER_TDL_PARSER_AST_NODE_HPP +#include #include +#include +#include #include +#include namespace spider::tdl::parser::ast { /** @@ -13,12 +17,90 @@ class Node { public: // Types enum class ErrorCodeEnum : uint8_t { - PlaceholderError = 1, + ChildIdOutOfBounds = 1, + ParentAlreadySet, }; using ErrorCode = ystdlib::error_handling::ErrorCode; + // Delete copy constructor and assignment operator + Node(Node const&) = delete; + auto operator=(Node const&) -> Node& = delete; + + // Default move constructor and assignment operator + Node(Node&&) = default; + auto operator=(Node&&) -> Node& = default; + + // Destructor + virtual ~Node() = default; + + // Methods + /** + * @return The parent node of this AST node, or nullptr if it has no parent. + */ + [[nodiscard]] auto get_parent() const noexcept -> Node const* { return m_parent; } + + /** + * @return The number of children this AST node has. + */ + [[nodiscard]] auto get_num_children() const noexcept -> size_t { return m_children.size(); } + + /** + * Gets a child node by its index. + * @param child_id + * @return A result containing a pointer to the child on success, or an error code indicating + * the failure: + * - ErrorCodeEnum::ChildIdOutOfBounds if the child ID is out of bounds. + */ + [[nodiscard]] auto get_child(size_t child_id) const + -> ystdlib::error_handling::Result; + + /** + * Visits the children of this AST node using the provided visitor function. + * @tparam ChildVisitor + * @param visitor + * @return A void result on success, or an error code indicating the failure: + * - Forwards `visitor`'s return values. + */ + template + requires( + std::is_invocable_r_v, ChildVisitor, Node const&> + ) + [[nodiscard]] auto visit_children(ChildVisitor visitor) const + -> ystdlib::error_handling::Result { + for (auto const& child : m_children) { + YSTDLIB_ERROR_HANDLING_TRYV(visitor(*child)); + } + return ystdlib::error_handling::success(); + } + +protected: + // Default constructor + Node() = default; + + /** + * Adds a child node to this AST node. + * @param child + * @return A void result on success, or an error code indicating the failure: + * - ErrorCodeEnum::ParentAlreadySet if the child node already has a parent set. + */ + [[nodiscard]] auto add_child(std::unique_ptr child) + -> ystdlib::error_handling::Result; + + /** + * Gets a child node by its index. + * NOTE: This method is unsafe. The caller must ensure the given ID is valid. + * @param child_id + * @return The child node at the specified index. + */ + [[nodiscard]] auto get_child_unsafe(size_t child_id) const -> Node* { + return m_children[child_id].get(); + } + private: + // Variables + std::vector> m_children; + Node const* m_parent = nullptr; }; } // namespace spider::tdl::parser::ast From fc5a746b4c626c93f5f0785958cf925f611b4653 Mon Sep 17 00:00:00 2001 From: LinZhihao-723 Date: Thu, 7 Aug 2025 10:43:36 -0400 Subject: [PATCH 02/24] Fix --- src/spider/tdl/parser/ast/Node.hpp | 5 ++++- tests/tdl/test-parser-ast.cpp | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/spider/tdl/parser/ast/Node.hpp b/src/spider/tdl/parser/ast/Node.hpp index faa6dd765..b24b750ca 100644 --- a/src/spider/tdl/parser/ast/Node.hpp +++ b/src/spider/tdl/parser/ast/Node.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -75,9 +76,11 @@ class Node { } protected: - // Default constructor + // Constructors Node() = default; + explicit Node(std::vector> children) : m_children(std::move(children)) {} + /** * Adds a child node to this AST node. * @param child diff --git a/tests/tdl/test-parser-ast.cpp b/tests/tdl/test-parser-ast.cpp index e439b0d4a..2ee0abecf 100644 --- a/tests/tdl/test-parser-ast.cpp +++ b/tests/tdl/test-parser-ast.cpp @@ -10,7 +10,7 @@ TEST_CASE("test-ast-node", "[tdl][ast][Node]") { using spider::tdl::parser::ast::Node; using ystdlib::error_handling::Result; - Result const result{Node::ErrorCode{Node::ErrorCodeEnum::PlaceholderError}}; + Result const result{Node::ErrorCode{Node::ErrorCodeEnum::ChildIdOutOfBounds}}; REQUIRE(result.has_error()); } } // namespace From 8dad68a6491cb16bb627f42bb8a005fa42151ab3 Mon Sep 17 00:00:00 2001 From: LinZhihao-723 Date: Thu, 7 Aug 2025 10:48:08 -0400 Subject: [PATCH 03/24] Remove children vector construction... --- src/spider/tdl/parser/ast/Node.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/spider/tdl/parser/ast/Node.hpp b/src/spider/tdl/parser/ast/Node.hpp index b24b750ca..e7bb01568 100644 --- a/src/spider/tdl/parser/ast/Node.hpp +++ b/src/spider/tdl/parser/ast/Node.hpp @@ -79,8 +79,6 @@ class Node { // Constructors Node() = default; - explicit Node(std::vector> children) : m_children(std::move(children)) {} - /** * Adds a child node to this AST node. * @param child From 208b76f81fd1a2699addaf2f37b39a82126dceb4 Mon Sep 17 00:00:00 2001 From: LinZhihao-723 Date: Thu, 7 Aug 2025 10:52:53 -0400 Subject: [PATCH 04/24] Apply coderabbit comments. --- src/spider/tdl/parser/ast/Node.cpp | 7 +++++++ src/spider/tdl/parser/ast/Node.hpp | 5 +++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/spider/tdl/parser/ast/Node.cpp b/src/spider/tdl/parser/ast/Node.cpp index caad6a425..4577d0ac9 100644 --- a/src/spider/tdl/parser/ast/Node.cpp +++ b/src/spider/tdl/parser/ast/Node.cpp @@ -21,6 +21,8 @@ auto NodeErrorCodeCategory ::message(Node::ErrorCodeEnum error_enum) const -> st switch (error_enum) { case Node::ErrorCodeEnum::ChildIdOutOfBounds: return "The child ID is out of bounds."; + case Node::ErrorCodeEnum::ChildIsNull: + return "The child node is NULL."; case Node::ErrorCodeEnum::ParentAlreadySet: return "The AST node's parent has already been set."; default: @@ -41,9 +43,14 @@ auto Node::get_child(size_t child_id) const -> Result { } auto Node::add_child(std::unique_ptr child) -> Result { + if (nullptr == child) { + return Node::ErrorCode{Node::ErrorCodeEnum::ChildIsNull}; + } + if (nullptr != child->get_parent()) { return Node::ErrorCode{Node::ErrorCodeEnum::ParentAlreadySet}; } + child->m_parent = this; m_children.emplace_back(std::move(child)); return ystdlib::error_handling::success(); diff --git a/src/spider/tdl/parser/ast/Node.hpp b/src/spider/tdl/parser/ast/Node.hpp index e7bb01568..916d903cc 100644 --- a/src/spider/tdl/parser/ast/Node.hpp +++ b/src/spider/tdl/parser/ast/Node.hpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include @@ -19,6 +18,7 @@ class Node { // Types enum class ErrorCodeEnum : uint8_t { ChildIdOutOfBounds = 1, + ChildIsNull, ParentAlreadySet, }; @@ -83,6 +83,7 @@ class Node { * Adds a child node to this AST node. * @param child * @return A void result on success, or an error code indicating the failure: + * - ErrorCodeEnum::ChildIsNull if `child` is NULL. * - ErrorCodeEnum::ParentAlreadySet if the child node already has a parent set. */ [[nodiscard]] auto add_child(std::unique_ptr child) @@ -94,7 +95,7 @@ class Node { * @param child_id * @return The child node at the specified index. */ - [[nodiscard]] auto get_child_unsafe(size_t child_id) const -> Node* { + [[nodiscard]] auto get_child_unsafe(size_t child_id) const -> Node const* { return m_children[child_id].get(); } From c2672f444fe62e3887ce1d7180e996f2312a5f2e Mon Sep 17 00:00:00 2001 From: LinZhihao-723 Date: Thu, 7 Aug 2025 11:25:07 -0400 Subject: [PATCH 05/24] Add serialization method. --- src/spider/tdl/parser/ast/Node.hpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/spider/tdl/parser/ast/Node.hpp b/src/spider/tdl/parser/ast/Node.hpp index 916d903cc..309fdce6d 100644 --- a/src/spider/tdl/parser/ast/Node.hpp +++ b/src/spider/tdl/parser/ast/Node.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -75,6 +76,17 @@ class Node { return ystdlib::error_handling::success(); } + /** + * Serializes this AST node and its children to a string representation. + * @param indentation_level The indentation level for pretty-printing. Each level of indentation + * is represented by 2 spaces. + * @return A result containing the string representation of this AST node, or an error code + * indicating the failure (implementation-defined). + */ + [[nodiscard]] virtual auto serialize_to_str(size_t indentation_level) const + -> ystdlib::error_handling::Result + = 0; + protected: // Constructors Node() = default; From 7e8c46fb69460a8637009e6226cb6f28252775a5 Mon Sep 17 00:00:00 2001 From: LinZhihao-723 Date: Thu, 7 Aug 2025 11:25:38 -0400 Subject: [PATCH 06/24] Remove default constructor. --- src/spider/tdl/parser/ast/Node.hpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/spider/tdl/parser/ast/Node.hpp b/src/spider/tdl/parser/ast/Node.hpp index 309fdce6d..0d5c8d712 100644 --- a/src/spider/tdl/parser/ast/Node.hpp +++ b/src/spider/tdl/parser/ast/Node.hpp @@ -88,9 +88,6 @@ class Node { = 0; protected: - // Constructors - Node() = default; - /** * Adds a child node to this AST node. * @param child From 802f7d4a3386e3207a921f0b8d29702da93c36e7 Mon Sep 17 00:00:00 2001 From: LinZhihao-723 Date: Thu, 7 Aug 2025 11:28:43 -0400 Subject: [PATCH 07/24] Use consistently. --- src/spider/tdl/parser/ast/Node.cpp | 12 ++++++------ src/spider/tdl/parser/ast/Node.hpp | 14 +++++++------- tests/tdl/test-parser-ast.cpp | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/spider/tdl/parser/ast/Node.cpp b/src/spider/tdl/parser/ast/Node.cpp index 4577d0ac9..862db8f84 100644 --- a/src/spider/tdl/parser/ast/Node.cpp +++ b/src/spider/tdl/parser/ast/Node.cpp @@ -19,8 +19,8 @@ auto NodeErrorCodeCategory::name() const noexcept -> char const* { template <> auto NodeErrorCodeCategory ::message(Node::ErrorCodeEnum error_enum) const -> std::string { switch (error_enum) { - case Node::ErrorCodeEnum::ChildIdOutOfBounds: - return "The child ID is out of bounds."; + case Node::ErrorCodeEnum::ChildIndexOutOfBounds: + return "The child index is out of bounds."; case Node::ErrorCodeEnum::ChildIsNull: return "The child node is NULL."; case Node::ErrorCodeEnum::ParentAlreadySet: @@ -35,11 +35,11 @@ namespace { using ystdlib::error_handling::Result; } // namespace -auto Node::get_child(size_t child_id) const -> Result { - if (m_children.size() <= child_id) { - return Node::ErrorCode{Node::ErrorCodeEnum::ChildIdOutOfBounds}; +auto Node::get_child(size_t child_idx) const -> Result { + if (m_children.size() <= child_idx) { + return Node::ErrorCode{Node::ErrorCodeEnum::ChildIndexOutOfBounds}; } - return get_child_unsafe(child_id); + return get_child_unsafe(child_idx); } auto Node::add_child(std::unique_ptr child) -> Result { diff --git a/src/spider/tdl/parser/ast/Node.hpp b/src/spider/tdl/parser/ast/Node.hpp index 0d5c8d712..d62ef3460 100644 --- a/src/spider/tdl/parser/ast/Node.hpp +++ b/src/spider/tdl/parser/ast/Node.hpp @@ -18,7 +18,7 @@ class Node { public: // Types enum class ErrorCodeEnum : uint8_t { - ChildIdOutOfBounds = 1, + ChildIndexOutOfBounds = 1, ChildIsNull, ParentAlreadySet, }; @@ -49,12 +49,12 @@ class Node { /** * Gets a child node by its index. - * @param child_id + * @param child_idx * @return A result containing a pointer to the child on success, or an error code indicating * the failure: * - ErrorCodeEnum::ChildIdOutOfBounds if the child ID is out of bounds. */ - [[nodiscard]] auto get_child(size_t child_id) const + [[nodiscard]] auto get_child(size_t child_idx) const -> ystdlib::error_handling::Result; /** @@ -100,12 +100,12 @@ class Node { /** * Gets a child node by its index. - * NOTE: This method is unsafe. The caller must ensure the given ID is valid. - * @param child_id + * NOTE: This method is unsafe. The caller must ensure the given index is valid. + * @param child_idx * @return The child node at the specified index. */ - [[nodiscard]] auto get_child_unsafe(size_t child_id) const -> Node const* { - return m_children[child_id].get(); + [[nodiscard]] auto get_child_unsafe(size_t child_idx) const -> Node const* { + return m_children[child_idx].get(); } private: diff --git a/tests/tdl/test-parser-ast.cpp b/tests/tdl/test-parser-ast.cpp index 2ee0abecf..7c44aa0a1 100644 --- a/tests/tdl/test-parser-ast.cpp +++ b/tests/tdl/test-parser-ast.cpp @@ -10,7 +10,7 @@ TEST_CASE("test-ast-node", "[tdl][ast][Node]") { using spider::tdl::parser::ast::Node; using ystdlib::error_handling::Result; - Result const result{Node::ErrorCode{Node::ErrorCodeEnum::ChildIdOutOfBounds}}; + Result const result{Node::ErrorCode{Node::ErrorCodeEnum::ChildIndexOutOfBounds}}; REQUIRE(result.has_error()); } } // namespace From f8b6898ca58f34f2692c26092116f6f29c69ff6c Mon Sep 17 00:00:00 2001 From: LinZhihao-723 Date: Thu, 7 Aug 2025 12:20:09 -0400 Subject: [PATCH 08/24] Implement identifier. --- src/spider/CMakeLists.txt | 6 ++- src/spider/tdl/parser/ast/Node.hpp | 3 ++ .../tdl/parser/ast/node_impl/Identifier.cpp | 16 +++++++ .../tdl/parser/ast/node_impl/Identifier.hpp | 42 +++++++++++++++++++ src/spider/tdl/parser/ast/utils.cpp | 13 ++++++ src/spider/tdl/parser/ast/utils.hpp | 17 ++++++++ tests/tdl/test-parser-ast.cpp | 21 +++++++++- 7 files changed, 115 insertions(+), 3 deletions(-) create mode 100644 src/spider/tdl/parser/ast/node_impl/Identifier.cpp create mode 100644 src/spider/tdl/parser/ast/node_impl/Identifier.hpp create mode 100644 src/spider/tdl/parser/ast/utils.cpp create mode 100644 src/spider/tdl/parser/ast/utils.hpp diff --git a/src/spider/CMakeLists.txt b/src/spider/CMakeLists.txt index 131022a86..6ac12c617 100644 --- a/src/spider/CMakeLists.txt +++ b/src/spider/CMakeLists.txt @@ -197,12 +197,16 @@ 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/utils.cpp CACHE INTERNAL "spider task definition language shared source files" ) set(SPIDER_TDL_SHARED_HEADERS tdl/parser/ast/Node.hpp + tdl/parser/ast/node_impl/Identifier.hpp + tdl/parser/ast/utils.hpp CACHE INTERNAL "spider task definition language shared header files" ) @@ -212,6 +216,6 @@ target_sources(spider_tdl PRIVATE ${SPIDER_TDL_SHARED_SOURCES}) target_sources(spider_tdl PUBLIC ${SPIDER_TDL_SHARED_HEADERS}) target_include_directories(spider_tdl PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/..) -target_link_libraries(spider_tdl PUBLIC ystdlib::error_handling) +target_link_libraries(spider_tdl PUBLIC ystdlib::error_handling fmt::fmt) add_library(spider::tdl ALIAS spider_tdl) diff --git a/src/spider/tdl/parser/ast/Node.hpp b/src/spider/tdl/parser/ast/Node.hpp index d62ef3460..8d95e42a7 100644 --- a/src/spider/tdl/parser/ast/Node.hpp +++ b/src/spider/tdl/parser/ast/Node.hpp @@ -88,6 +88,9 @@ class Node { = 0; protected: + // Constructor + Node() = default; + /** * Adds a child node to this AST node. * @param child diff --git a/src/spider/tdl/parser/ast/node_impl/Identifier.cpp b/src/spider/tdl/parser/ast/node_impl/Identifier.cpp new file mode 100644 index 000000000..0f6bca88e --- /dev/null +++ b/src/spider/tdl/parser/ast/node_impl/Identifier.cpp @@ -0,0 +1,16 @@ +#include "Identifier.hpp" + +#include +#include + +#include +#include + +#include + +namespace spider::tdl::parser::ast::node_impl { +auto Identifier::serialize_to_str(size_t indentation_level) const + -> ystdlib::error_handling::Result { + return fmt::format("{}{}: {}", create_indentation(indentation_level), "Identifier", m_name); +} +} // namespace spider::tdl::parser::ast::node_impl diff --git a/src/spider/tdl/parser/ast/node_impl/Identifier.hpp b/src/spider/tdl/parser/ast/node_impl/Identifier.hpp new file mode 100644 index 000000000..2ae0e69b4 --- /dev/null +++ b/src/spider/tdl/parser/ast/node_impl/Identifier.hpp @@ -0,0 +1,42 @@ +#ifndef SPIDER_TDL_PARSER_AST_IDENTIFIER_HPP +#define SPIDER_TDL_PARSER_AST_IDENTIFIER_HPP + +#include +#include +#include +#include +#include + +#include + +#include + +namespace spider::tdl::parser::ast::node_impl { +class Identifier : public Node { +public: + // Factory function + /** + * @param name + * @return A unique pointer to a new `Identifier` instance with the given name. + */ + static auto create(std::string name) -> std::unique_ptr { + return std::make_unique(Identifier{std::move(name)}); + } + + // Methods implementing `Node` + [[nodiscard]] auto serialize_to_str(size_t indentation_level) const + -> ystdlib::error_handling::Result override; + + // Methods + [[nodiscard]] auto get_name() const noexcept -> std::string_view { return m_name; } + +private: + // Constructor + explicit Identifier(std::string name) noexcept : m_name{std::move(name)} {} + + // Variables + std::string m_name; +}; +} // namespace spider::tdl::parser::ast::node_impl + +#endif // SPIDER_TDL_PARSER_AST_IDENTIFIER_HPP diff --git a/src/spider/tdl/parser/ast/utils.cpp b/src/spider/tdl/parser/ast/utils.cpp new file mode 100644 index 000000000..b99cca5bf --- /dev/null +++ b/src/spider/tdl/parser/ast/utils.cpp @@ -0,0 +1,13 @@ +#include "utils.hpp" + +#include +#include + +namespace spider::tdl::parser::ast { +auto create_indentation(size_t indentation_level) -> std::string { + // We can't use braced init list for the following string initialization, as the compiler will + // treat the init list as chars. + // NOLINTNEXTLINE(modernize-return-braced-init-list) + return std::string(indentation_level * 2, ' '); +} +} // namespace spider::tdl::parser::ast diff --git a/src/spider/tdl/parser/ast/utils.hpp b/src/spider/tdl/parser/ast/utils.hpp new file mode 100644 index 000000000..2a52e4a6d --- /dev/null +++ b/src/spider/tdl/parser/ast/utils.hpp @@ -0,0 +1,17 @@ +#ifndef SPIDER_TDL_PARSER_UTILS_HPP +#define SPIDER_TDL_PARSER_UTILS_HPP + +#include +#include + +namespace spider::tdl::parser::ast { +/** + * Creates a string with the specified number of indentation levels. + * Each level of indentation is represented by 2 spaces. + * @param indentation_level The number of indentation levels to create. + * @return A string containing the specified number of indentation levels. + */ +[[nodiscard]] auto create_indentation(size_t indentation_level) -> std::string; +} // namespace spider::tdl::parser::ast + +#endif // SPIDER_TDL_PARSER_UTILS_HPP diff --git a/tests/tdl/test-parser-ast.cpp b/tests/tdl/test-parser-ast.cpp index 7c44aa0a1..6591b3401 100644 --- a/tests/tdl/test-parser-ast.cpp +++ b/tests/tdl/test-parser-ast.cpp @@ -1,17 +1,34 @@ // NOLINTBEGIN(cert-err58-cpp,cppcoreguidelines-avoid-do-while,readability-function-cognitive-complexity,cppcoreguidelines-avoid-non-const-global-variables,cppcoreguidelines-avoid-c-arrays,modernize-avoid-c-arrays) +#include +#include + #include #include #include +#include namespace { TEST_CASE("test-ast-node", "[tdl][ast][Node]") { using spider::tdl::parser::ast::Node; + using spider::tdl::parser::ast::node_impl::Identifier; using ystdlib::error_handling::Result; - Result const result{Node::ErrorCode{Node::ErrorCodeEnum::ChildIndexOutOfBounds}}; - REQUIRE(result.has_error()); + SECTION("Identifier") { + constexpr std::string_view cTestName{"test_name"}; + constexpr std::string_view cSerializedIdentifier{"Identifier: test_name"}; + + auto const identifier{Identifier::create(std::string{cTestName})}; + REQUIRE(nullptr != identifier); + + REQUIRE(nullptr == identifier->get_parent()); + REQUIRE(identifier->get_name() == cTestName); + + auto const serialized_result{identifier->serialize_to_str(0)}; + REQUIRE_FALSE(serialized_result.has_error()); + REQUIRE(serialized_result.value() == cSerializedIdentifier); + } } } // namespace From dbbc492349ef21c8904e3ca90bf8940ed564e50e Mon Sep 17 00:00:00 2001 From: LinZhihao-723 Date: Thu, 7 Aug 2025 12:56:01 -0400 Subject: [PATCH 09/24] Fix cmake format. --- src/spider/CMakeLists.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/spider/CMakeLists.txt b/src/spider/CMakeLists.txt index 6ac12c617..db95d034f 100644 --- a/src/spider/CMakeLists.txt +++ b/src/spider/CMakeLists.txt @@ -216,6 +216,11 @@ target_sources(spider_tdl PRIVATE ${SPIDER_TDL_SHARED_SOURCES}) target_sources(spider_tdl PUBLIC ${SPIDER_TDL_SHARED_HEADERS}) target_include_directories(spider_tdl PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/..) -target_link_libraries(spider_tdl PUBLIC ystdlib::error_handling fmt::fmt) +target_link_libraries( + spider_tdl + PUBLIC + ystdlib::error_handling + fmt::fmt +) add_library(spider::tdl ALIAS spider_tdl) From fea5b89113a55b294e8b36a3e3a6aca91926012a Mon Sep 17 00:00:00 2001 From: LinZhihao-723 Date: Thu, 7 Aug 2025 13:47:47 -0400 Subject: [PATCH 10/24] Update the header guard. --- src/spider/tdl/parser/ast/node_impl/Identifier.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/spider/tdl/parser/ast/node_impl/Identifier.hpp b/src/spider/tdl/parser/ast/node_impl/Identifier.hpp index 2ae0e69b4..708a5ccf9 100644 --- a/src/spider/tdl/parser/ast/node_impl/Identifier.hpp +++ b/src/spider/tdl/parser/ast/node_impl/Identifier.hpp @@ -1,5 +1,5 @@ -#ifndef SPIDER_TDL_PARSER_AST_IDENTIFIER_HPP -#define SPIDER_TDL_PARSER_AST_IDENTIFIER_HPP +#ifndef SPIDER_TDL_PARSER_AST_NODE_IMPL_IDENTIFIER_HPP +#define SPIDER_TDL_PARSER_AST_NODE_IMPL_IDENTIFIER_HPP #include #include @@ -39,4 +39,4 @@ class Identifier : public Node { }; } // namespace spider::tdl::parser::ast::node_impl -#endif // SPIDER_TDL_PARSER_AST_IDENTIFIER_HPP +#endif // SPIDER_TDL_PARSER_AST_NODE_IMPL_IDENTIFIER_HPP From 1a26b6e4a080c63d72e22b6fa9154e2a73f592ba Mon Sep 17 00:00:00 2001 From: LinZhihao-723 Date: Thu, 7 Aug 2025 14:17:08 -0400 Subject: [PATCH 11/24] Update factory function's return type... --- src/spider/tdl/parser/ast/node_impl/Identifier.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spider/tdl/parser/ast/node_impl/Identifier.hpp b/src/spider/tdl/parser/ast/node_impl/Identifier.hpp index 708a5ccf9..a78b14a61 100644 --- a/src/spider/tdl/parser/ast/node_impl/Identifier.hpp +++ b/src/spider/tdl/parser/ast/node_impl/Identifier.hpp @@ -19,7 +19,7 @@ class Identifier : public Node { * @param name * @return A unique pointer to a new `Identifier` instance with the given name. */ - static auto create(std::string name) -> std::unique_ptr { + static auto create(std::string name) -> std::unique_ptr { return std::make_unique(Identifier{std::move(name)}); } From 9f94867cad6e1166667efb4bcbd4648144d39be6 Mon Sep 17 00:00:00 2001 From: LinZhihao-723 Date: Thu, 7 Aug 2025 14:37:49 -0400 Subject: [PATCH 12/24] Update serialization format. --- src/spider/tdl/parser/ast/node_impl/Identifier.cpp | 2 +- tests/tdl/test-parser-ast.cpp | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/spider/tdl/parser/ast/node_impl/Identifier.cpp b/src/spider/tdl/parser/ast/node_impl/Identifier.cpp index 0f6bca88e..8d58a7eb1 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("{}{}: {}", create_indentation(indentation_level), "Identifier", m_name); + return fmt::format("{}[Identifier]: {}", create_indentation(indentation_level), m_name); } } // namespace spider::tdl::parser::ast::node_impl diff --git a/tests/tdl/test-parser-ast.cpp b/tests/tdl/test-parser-ast.cpp index 6591b3401..00fea8b06 100644 --- a/tests/tdl/test-parser-ast.cpp +++ b/tests/tdl/test-parser-ast.cpp @@ -17,9 +17,10 @@ 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 identifier{Identifier::create(std::string{cTestName})}; + auto const node{Identifier::create(std::string{cTestName})}; + auto const* identifier{dynamic_cast(node.get())}; REQUIRE(nullptr != identifier); REQUIRE(nullptr == identifier->get_parent()); From 41058899f7fc5e40665f4db7077827b67910d211 Mon Sep 17 00:00:00 2001 From: LinZhihao-723 Date: Thu, 7 Aug 2025 16:01:44 -0400 Subject: [PATCH 13/24] Implement types. --- src/spider/CMakeLists.txt | 15 +++ src/spider/tdl/parser/ast/FloatSpec.hpp | 14 +++ src/spider/tdl/parser/ast/IntSpec.hpp | 16 ++++ src/spider/tdl/parser/ast/Node.cpp | 4 + src/spider/tdl/parser/ast/Node.hpp | 2 + src/spider/tdl/parser/ast/node_impl/Type.hpp | 11 +++ .../ast/node_impl/type_impl/Container.hpp | 11 +++ .../ast/node_impl/type_impl/Primitive.hpp | 11 +++ .../type_impl/container_impl/List.cpp | 34 +++++++ .../type_impl/container_impl/List.hpp | 44 +++++++++ .../type_impl/container_impl/Map.cpp | 95 +++++++++++++++++++ .../type_impl/container_impl/Map.hpp | 66 +++++++++++++ .../type_impl/primitive_impl/Bool.cpp | 16 ++++ .../type_impl/primitive_impl/Bool.hpp | 34 +++++++ .../type_impl/primitive_impl/Float.cpp | 20 ++++ .../type_impl/primitive_impl/Float.hpp | 42 ++++++++ .../type_impl/primitive_impl/Int.cpp | 20 ++++ .../type_impl/primitive_impl/Int.hpp | 42 ++++++++ src/spider/tdl/parser/ast/utils.cpp | 33 +++++++ src/spider/tdl/parser/ast/utils.hpp | 48 ++++++++++ 20 files changed, 578 insertions(+) create mode 100644 src/spider/tdl/parser/ast/FloatSpec.hpp create mode 100644 src/spider/tdl/parser/ast/IntSpec.hpp create mode 100644 src/spider/tdl/parser/ast/node_impl/Type.hpp create mode 100644 src/spider/tdl/parser/ast/node_impl/type_impl/Container.hpp create mode 100644 src/spider/tdl/parser/ast/node_impl/type_impl/Primitive.hpp create mode 100644 src/spider/tdl/parser/ast/node_impl/type_impl/container_impl/List.cpp create mode 100644 src/spider/tdl/parser/ast/node_impl/type_impl/container_impl/List.hpp create mode 100644 src/spider/tdl/parser/ast/node_impl/type_impl/container_impl/Map.cpp create mode 100644 src/spider/tdl/parser/ast/node_impl/type_impl/container_impl/Map.hpp create mode 100644 src/spider/tdl/parser/ast/node_impl/type_impl/primitive_impl/Bool.cpp create mode 100644 src/spider/tdl/parser/ast/node_impl/type_impl/primitive_impl/Bool.hpp create mode 100644 src/spider/tdl/parser/ast/node_impl/type_impl/primitive_impl/Float.cpp create mode 100644 src/spider/tdl/parser/ast/node_impl/type_impl/primitive_impl/Float.hpp create mode 100644 src/spider/tdl/parser/ast/node_impl/type_impl/primitive_impl/Int.cpp create mode 100644 src/spider/tdl/parser/ast/node_impl/type_impl/primitive_impl/Int.hpp diff --git a/src/spider/CMakeLists.txt b/src/spider/CMakeLists.txt index db95d034f..fa2a790c5 100644 --- a/src/spider/CMakeLists.txt +++ b/src/spider/CMakeLists.txt @@ -198,6 +198,11 @@ 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/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 + tdl/parser/ast/node_impl/type_impl/primitive_impl/Float.cpp + tdl/parser/ast/node_impl/type_impl/primitive_impl/Int.cpp tdl/parser/ast/utils.cpp CACHE INTERNAL "spider task definition language shared source files" @@ -205,7 +210,17 @@ set(SPIDER_TDL_SHARED_SOURCES set(SPIDER_TDL_SHARED_HEADERS tdl/parser/ast/Node.hpp + tdl/parser/ast/FloatSpec.hpp + tdl/parser/ast/IntSpec.hpp tdl/parser/ast/node_impl/Identifier.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 + tdl/parser/ast/node_impl/type_impl/container_impl/Map.hpp + tdl/parser/ast/node_impl/type_impl/Primitive.hpp + tdl/parser/ast/node_impl/type_impl/primitive_impl/Bool.hpp + tdl/parser/ast/node_impl/type_impl/primitive_impl/Float.hpp + tdl/parser/ast/node_impl/type_impl/primitive_impl/Int.hpp tdl/parser/ast/utils.hpp CACHE INTERNAL "spider task definition language shared header files" diff --git a/src/spider/tdl/parser/ast/FloatSpec.hpp b/src/spider/tdl/parser/ast/FloatSpec.hpp new file mode 100644 index 000000000..74e74406f --- /dev/null +++ b/src/spider/tdl/parser/ast/FloatSpec.hpp @@ -0,0 +1,14 @@ +#ifndef SPIDER_TDL_PARSER_AST_FLOATSPEC_HPP +#define SPIDER_TDL_PARSER_AST_FLOATSPEC_HPP + +#include + +namespace spider::tdl::parser::ast { +// Float type specifications used in the AST. +enum class FloatSpec : uint8_t { + Float, + Double, +}; +} // namespace spider::tdl::parser::ast + +#endif // SPIDER_TDL_PARSER_AST_FLOATSPEC_HPP diff --git a/src/spider/tdl/parser/ast/IntSpec.hpp b/src/spider/tdl/parser/ast/IntSpec.hpp new file mode 100644 index 000000000..1dd68cb48 --- /dev/null +++ b/src/spider/tdl/parser/ast/IntSpec.hpp @@ -0,0 +1,16 @@ +#ifndef SPIDER_TDL_PARSER_AST_INTSPEC_HPP +#define SPIDER_TDL_PARSER_AST_INTSPEC_HPP + +#include + +namespace spider::tdl::parser::ast { +// Integer type specifications used in the AST. +enum class IntSpec : uint8_t { + Int8, + Int16, + Int32, + Int64, +}; +} // namespace spider::tdl::parser::ast + +#endif // SPIDER_TDL_PARSER_AST_INTSPEC_HPP diff --git a/src/spider/tdl/parser/ast/Node.cpp b/src/spider/tdl/parser/ast/Node.cpp index 862db8f84..4dfb40c2c 100644 --- a/src/spider/tdl/parser/ast/Node.cpp +++ b/src/spider/tdl/parser/ast/Node.cpp @@ -25,6 +25,10 @@ auto NodeErrorCodeCategory ::message(Node::ErrorCodeEnum error_enum) const -> st return "The child node is NULL."; case Node::ErrorCodeEnum::ParentAlreadySet: return "The AST node's parent has already been set."; + case Node::ErrorCodeEnum::UnexpectedChildNodeType: + return "The child node type is unexpected."; + case Node::ErrorCodeEnum::UnknownTypeSpec: + return "The type spec is unknown."; default: return "Unknown error code enum"; } diff --git a/src/spider/tdl/parser/ast/Node.hpp b/src/spider/tdl/parser/ast/Node.hpp index 8d95e42a7..56e8ff4af 100644 --- a/src/spider/tdl/parser/ast/Node.hpp +++ b/src/spider/tdl/parser/ast/Node.hpp @@ -21,6 +21,8 @@ class Node { ChildIndexOutOfBounds = 1, ChildIsNull, ParentAlreadySet, + UnexpectedChildNodeType, + UnknownTypeSpec, }; using ErrorCode = ystdlib::error_handling::ErrorCode; diff --git a/src/spider/tdl/parser/ast/node_impl/Type.hpp b/src/spider/tdl/parser/ast/node_impl/Type.hpp new file mode 100644 index 000000000..cd4dbb1fe --- /dev/null +++ b/src/spider/tdl/parser/ast/node_impl/Type.hpp @@ -0,0 +1,11 @@ +#ifndef SPIDER_TDL_PARSER_AST_NODE_IMPL_TYPE_HPP +#define SPIDER_TDL_PARSER_AST_NODE_IMPL_TYPE_HPP + +#include + +namespace spider::tdl::parser::ast::node_impl { +// Abstract base class for all type nodes in the AST. +class Type : public Node {}; +} // namespace spider::tdl::parser::ast::node_impl + +#endif // SPIDER_TDL_PARSER_AST_NODE_IMPL_TYPE_HPP diff --git a/src/spider/tdl/parser/ast/node_impl/type_impl/Container.hpp b/src/spider/tdl/parser/ast/node_impl/type_impl/Container.hpp new file mode 100644 index 000000000..0b361cde3 --- /dev/null +++ b/src/spider/tdl/parser/ast/node_impl/type_impl/Container.hpp @@ -0,0 +1,11 @@ +#ifndef SPIDER_TDL_PARSER_AST_NODE_IMPL_TYPE_IMPL_CONTAINER_HPP +#define SPIDER_TDL_PARSER_AST_NODE_IMPL_TYPE_IMPL_CONTAINER_HPP + +#include + +namespace spider::tdl::parser::ast::node_impl::type_impl { +// Abstract base class for all container type nodes in the AST. +class Container : public Type {}; +} // namespace spider::tdl::parser::ast::node_impl::type_impl + +#endif // SPIDER_TDL_PARSER_AST_NODE_IMPL_TYPE_IMPL_CONTAINER_HPP diff --git a/src/spider/tdl/parser/ast/node_impl/type_impl/Primitive.hpp b/src/spider/tdl/parser/ast/node_impl/type_impl/Primitive.hpp new file mode 100644 index 000000000..76edee4ef --- /dev/null +++ b/src/spider/tdl/parser/ast/node_impl/type_impl/Primitive.hpp @@ -0,0 +1,11 @@ +#ifndef SPIDER_TDL_PARSER_AST_NODE_IMPL_TYPE_IMPL_PRIMITIVE_HPP +#define SPIDER_TDL_PARSER_AST_NODE_IMPL_TYPE_IMPL_PRIMITIVE_HPP + +#include + +namespace spider::tdl::parser::ast::node_impl::type_impl { +// Abstract base class for all primitive type nodes in the AST. +class Primitive : public Type {}; +} // namespace spider::tdl::parser::ast::node_impl::type_impl + +#endif // SPIDER_TDL_PARSER_AST_NODE_IMPL_TYPE_IMPL_PRIMITIVE_HPP diff --git a/src/spider/tdl/parser/ast/node_impl/type_impl/container_impl/List.cpp b/src/spider/tdl/parser/ast/node_impl/type_impl/container_impl/List.cpp new file mode 100644 index 000000000..f26a730f1 --- /dev/null +++ b/src/spider/tdl/parser/ast/node_impl/type_impl/container_impl/List.cpp @@ -0,0 +1,34 @@ +#include "List.hpp" + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +namespace spider::tdl::parser::ast::node_impl::type_impl::container_impl { +auto List::create(std::unique_ptr element_type) + -> ystdlib::error_handling::Result> { + YSTDLIB_ERROR_HANDLING_TRYV(validate_child_node_type(element_type.get())); + + auto list{std::make_unique(List{})}; + YSTDLIB_ERROR_HANDLING_TRYV(list->add_child(std::move(element_type))); + return list; +} + +auto List::serialize_to_str(size_t indentation_level) const + -> ystdlib::error_handling::Result { + return fmt::format( + "{}[Type[Container[List]]]:\n{}ElementType:\n{}", + create_indentation(indentation_level), + create_indentation(indentation_level + 1), + YSTDLIB_ERROR_HANDLING_TRYX(get_element_type()->serialize_to_str(indentation_level + 2)) + ); +} +} // namespace spider::tdl::parser::ast::node_impl::type_impl::container_impl diff --git a/src/spider/tdl/parser/ast/node_impl/type_impl/container_impl/List.hpp b/src/spider/tdl/parser/ast/node_impl/type_impl/container_impl/List.hpp new file mode 100644 index 000000000..9da0404ec --- /dev/null +++ b/src/spider/tdl/parser/ast/node_impl/type_impl/container_impl/List.hpp @@ -0,0 +1,44 @@ +#ifndef SPIDER_TDL_PARSER_AST_NODE_IMPL_TYPE_IMPL_CONTAINER_IMPL_LIST_HPP +#define SPIDER_TDL_PARSER_AST_NODE_IMPL_TYPE_IMPL_CONTAINER_IMPL_LIST_HPP + +#include +#include +#include + +#include + +#include +#include +#include + +namespace spider::tdl::parser::ast::node_impl::type_impl::container_impl { +class List : public Container { +public: + // Factory function + /** + * @param element_type The type of elements in the list. + * @return A result containing a unique pointer to a new `List` 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 element_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_element_type() const noexcept -> Type const* { + // The factory function ensures that the first child is of type `Type`. + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-static-cast-downcast) + return static_cast(get_child_unsafe(0)); + } + +private: + // Constructor + List() = default; +}; +} // namespace spider::tdl::parser::ast::node_impl::type_impl::container_impl + +#endif // SPIDER_TDL_PARSER_AST_NODE_IMPL_TYPE_IMPL_CONTAINER_IMPL_LIST_HPP diff --git a/src/spider/tdl/parser/ast/node_impl/type_impl/container_impl/Map.cpp b/src/spider/tdl/parser/ast/node_impl/type_impl/container_impl/Map.cpp new file mode 100644 index 000000000..536fc5717 --- /dev/null +++ b/src/spider/tdl/parser/ast/node_impl/type_impl/container_impl/Map.cpp @@ -0,0 +1,95 @@ +#include "Map.hpp" + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +using spider::tdl::parser::ast::node_impl::type_impl::container_impl::Map; +using MapErrorCodeCategory = ystdlib::error_handling::ErrorCategory; + +template <> +auto MapErrorCodeCategory::name() const noexcept -> char const* { + return "spider::tdl::parser::ast::node_impl::type_impl::container_impl::Map"; +} + +template <> +auto MapErrorCodeCategory::message(Map::ErrorCodeEnum error_enum) const -> std::string { + switch (error_enum) { + case Map::ErrorCodeEnum::UnsupportedKeyType: + return "Unsupported key type for Map."; + default: + return "Unknown error code enum"; + } +} + +namespace spider::tdl::parser::ast::node_impl::type_impl::container_impl { +namespace { +using spider::tdl::parser::ast::node_impl::type_impl::primitive_impl::Int; + +/** + * Given a key type, checks if it is supported as a key type for a Map. + * @param key_type + * @return Whether the key type is supported. + */ +[[nodiscard]] auto is_supported_key_type(Type const* key_type) -> bool; + +auto is_supported_key_type(Type const* key_type) -> bool { + if (nullptr != dynamic_cast(key_type)) { + return true; + } + + auto const* list_type{dynamic_cast(key_type)}; + if (nullptr == list_type) { + return false; + } + + auto const* list_element_type{list_type->get_element_type()}; + if (auto const* int_type{dynamic_cast(list_element_type)}; nullptr != int_type) { + if (int_type->get_spec() != IntSpec::Int8) { + return false; + } + return true; + } + return false; +} +} // namespace + +auto Map::create(std::unique_ptr key_type, std::unique_ptr value_type) + -> ystdlib::error_handling::Result> { + YSTDLIB_ERROR_HANDLING_TRYV(validate_child_node_type(key_type.get())); + YSTDLIB_ERROR_HANDLING_TRYV(validate_child_node_type(value_type.get())); + + auto map{std::make_unique(Map{})}; + YSTDLIB_ERROR_HANDLING_TRYV(map->add_child(std::move(key_type))); + YSTDLIB_ERROR_HANDLING_TRYV(map->add_child(std::move(value_type))); + + if (false == is_supported_key_type(map->get_key_type())) { + return Map::ErrorCode{Map::ErrorCodeEnum::UnsupportedKeyType}; + } + return map; +} + +auto Map::serialize_to_str(size_t indentation_level) const + -> ystdlib::error_handling::Result { + return fmt::format( + "{}[Type[Container[Map]]]:\n{}KeyTpe:\n{}\n{}ValueType:\n{}", + create_indentation(indentation_level), + create_indentation(indentation_level + 1), + YSTDLIB_ERROR_HANDLING_TRYX(get_key_type()->serialize_to_str(indentation_level + 2)), + create_indentation(indentation_level + 1), + YSTDLIB_ERROR_HANDLING_TRYX(get_value_type()->serialize_to_str(indentation_level + 2)) + ); +} +} // namespace spider::tdl::parser::ast::node_impl::type_impl::container_impl diff --git a/src/spider/tdl/parser/ast/node_impl/type_impl/container_impl/Map.hpp b/src/spider/tdl/parser/ast/node_impl/type_impl/container_impl/Map.hpp new file mode 100644 index 000000000..621ce4335 --- /dev/null +++ b/src/spider/tdl/parser/ast/node_impl/type_impl/container_impl/Map.hpp @@ -0,0 +1,66 @@ +#ifndef SPIDER_TDL_PARSER_AST_NODE_IMPL_TYPE_IMPL_CONTAINER_IMPL_MAP_HPP +#define SPIDER_TDL_PARSER_AST_NODE_IMPL_TYPE_IMPL_CONTAINER_IMPL_MAP_HPP + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +namespace spider::tdl::parser::ast::node_impl::type_impl::container_impl { +class Map : public Container { +public: + // Types + enum class ErrorCodeEnum : uint8_t { + UnsupportedKeyType = 1, + }; + + using ErrorCode = ystdlib::error_handling::ErrorCode; + + // Factory function + /** + * @param key_type + * @param value_type + * @return A result containing a unique pointer to a new `Map` instance with the given name on + * success, or an error code indicating the failure: + * - Map::ErrorCodeEnum::UnsupportedKeyType if the `key_type` is not supported. + * - Forwards `validate_child_node_type`'s return values. + */ + [[nodiscard]] static auto + create(std::unique_ptr key_type, std::unique_ptr value_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_key_type() const -> Type const* { + // The factory function ensures that the first child is of type `Type`. + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-static-cast-downcast) + return static_cast(get_child_unsafe(0)); + } + + [[nodiscard]] auto get_value_type() const -> Type const* { + // The factory function ensures that the first child is of type `Type`. + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-static-cast-downcast) + return static_cast(get_child_unsafe(1)); + } + +private: + // Constructor + Map() = default; +}; +} // namespace spider::tdl::parser::ast::node_impl::type_impl::container_impl + +YSTDLIB_ERROR_HANDLING_MARK_AS_ERROR_CODE_ENUM( + spider::tdl::parser::ast::node_impl::type_impl::container_impl::Map::ErrorCodeEnum +); + +#endif // SPIDER_TDL_PARSER_AST_NODE_IMPL_TYPE_IMPL_CONTAINER_IMPL_MAP_HPP diff --git a/src/spider/tdl/parser/ast/node_impl/type_impl/primitive_impl/Bool.cpp b/src/spider/tdl/parser/ast/node_impl/type_impl/primitive_impl/Bool.cpp new file mode 100644 index 000000000..d19a1def0 --- /dev/null +++ b/src/spider/tdl/parser/ast/node_impl/type_impl/primitive_impl/Bool.cpp @@ -0,0 +1,16 @@ +#include "Bool.hpp" + +#include +#include + +#include +#include + +#include + +namespace spider::tdl::parser::ast::node_impl::type_impl::primitive_impl { +auto Bool::serialize_to_str(size_t indentation_level) const + -> ystdlib::error_handling::Result { + return fmt::format("{}[Type[Primitive[Bool]]]", create_indentation(indentation_level)); +} +} // namespace spider::tdl::parser::ast::node_impl::type_impl::primitive_impl diff --git a/src/spider/tdl/parser/ast/node_impl/type_impl/primitive_impl/Bool.hpp b/src/spider/tdl/parser/ast/node_impl/type_impl/primitive_impl/Bool.hpp new file mode 100644 index 000000000..3afda1814 --- /dev/null +++ b/src/spider/tdl/parser/ast/node_impl/type_impl/primitive_impl/Bool.hpp @@ -0,0 +1,34 @@ +#ifndef SPIDER_TDL_PARSER_AST_NODE_IMPL_TYPE_IMPL_PRIMITIVE_IMPL_BOOL_HPP +#define SPIDER_TDL_PARSER_AST_NODE_IMPL_TYPE_IMPL_PRIMITIVE_IMPL_BOOL_HPP + +#include +#include +#include + +#include + +#include +#include + +namespace spider::tdl::parser::ast::node_impl::type_impl::primitive_impl { +class Bool : public Primitive { +public: + // Factory function + /** + * @return A unique pointer to a new `Bool` instance. + */ + [[nodiscard]] static auto create() -> std::unique_ptr { + return std::make_unique(Bool{}); + } + + // Methods implementing `Node` + [[nodiscard]] auto serialize_to_str(size_t indentation_level) const + -> ystdlib::error_handling::Result override; + +private: + // Constructor + explicit Bool() = default; +}; +} // namespace spider::tdl::parser::ast::node_impl::type_impl::primitive_impl + +#endif // SPIDER_TDL_PARSER_AST_NODE_IMPL_TYPE_IMPL_PRIMITIVE_IMPL_BOOL_HPP diff --git a/src/spider/tdl/parser/ast/node_impl/type_impl/primitive_impl/Float.cpp b/src/spider/tdl/parser/ast/node_impl/type_impl/primitive_impl/Float.cpp new file mode 100644 index 000000000..4b08c4c2e --- /dev/null +++ b/src/spider/tdl/parser/ast/node_impl/type_impl/primitive_impl/Float.cpp @@ -0,0 +1,20 @@ +#include "Float.hpp" + +#include +#include + +#include +#include + +#include + +namespace spider::tdl::parser::ast::node_impl::type_impl::primitive_impl { +auto Float::serialize_to_str(size_t indentation_level) const + -> ystdlib::error_handling::Result { + return fmt::format( + "{}[Type[Primitive[Float]]]: {}", + create_indentation(indentation_level), + YSTDLIB_ERROR_HANDLING_TRYX(serialize_float_spec(m_spec)) + ); +} +} // namespace spider::tdl::parser::ast::node_impl::type_impl::primitive_impl diff --git a/src/spider/tdl/parser/ast/node_impl/type_impl/primitive_impl/Float.hpp b/src/spider/tdl/parser/ast/node_impl/type_impl/primitive_impl/Float.hpp new file mode 100644 index 000000000..561708628 --- /dev/null +++ b/src/spider/tdl/parser/ast/node_impl/type_impl/primitive_impl/Float.hpp @@ -0,0 +1,42 @@ +#ifndef SPIDER_TDL_PARSER_AST_NODE_IMPL_TYPE_IMPL_PRIMITIVE_IMPL_FLOAT_HPP +#define SPIDER_TDL_PARSER_AST_NODE_IMPL_TYPE_IMPL_PRIMITIVE_IMPL_FLOAT_HPP + +#include +#include +#include + +#include + +#include +#include +#include + +namespace spider::tdl::parser::ast::node_impl::type_impl::primitive_impl { +class Float : public Primitive { +public: + // Factory function + /** + * @param spec + * @return A unique pointer to a new `Float` instance with the given type spec. + */ + [[nodiscard]] static auto create(FloatSpec spec) -> std::unique_ptr { + return std::make_unique(Float{spec}); + } + + // Methods implementing `Node` + [[nodiscard]] auto serialize_to_str(size_t indentation_level) const + -> ystdlib::error_handling::Result override; + + // Methods + [[nodiscard]] auto get_spec() const -> FloatSpec { return m_spec; } + +private: + // Constructor + explicit Float(FloatSpec spec) : m_spec{spec} {} + + // Variables + FloatSpec m_spec; +}; +} // namespace spider::tdl::parser::ast::node_impl::type_impl::primitive_impl + +#endif // SPIDER_TDL_PARSER_AST_NODE_IMPL_TYPE_IMPL_PRIMITIVE_IMPL_FLOAT_HPP diff --git a/src/spider/tdl/parser/ast/node_impl/type_impl/primitive_impl/Int.cpp b/src/spider/tdl/parser/ast/node_impl/type_impl/primitive_impl/Int.cpp new file mode 100644 index 000000000..f1e2c25a1 --- /dev/null +++ b/src/spider/tdl/parser/ast/node_impl/type_impl/primitive_impl/Int.cpp @@ -0,0 +1,20 @@ +#include "Int.hpp" + +#include +#include + +#include +#include + +#include + +namespace spider::tdl::parser::ast::node_impl::type_impl::primitive_impl { +auto Int::serialize_to_str(size_t indentation_level) const + -> ystdlib::error_handling::Result { + return fmt::format( + "{}[Type[Primitive[Int]]]: {}", + create_indentation(indentation_level), + YSTDLIB_ERROR_HANDLING_TRYX(serialize_int_spec(m_spec)) + ); +} +} // namespace spider::tdl::parser::ast::node_impl::type_impl::primitive_impl diff --git a/src/spider/tdl/parser/ast/node_impl/type_impl/primitive_impl/Int.hpp b/src/spider/tdl/parser/ast/node_impl/type_impl/primitive_impl/Int.hpp new file mode 100644 index 000000000..dcc629803 --- /dev/null +++ b/src/spider/tdl/parser/ast/node_impl/type_impl/primitive_impl/Int.hpp @@ -0,0 +1,42 @@ +#ifndef SPIDER_TDL_PARSER_AST_NODE_IMPL_TYPE_IMPL_PRIMITIVE_IMPL_INT_HPP +#define SPIDER_TDL_PARSER_AST_NODE_IMPL_TYPE_IMPL_PRIMITIVE_IMPL_INT_HPP + +#include +#include +#include + +#include + +#include +#include +#include + +namespace spider::tdl::parser::ast::node_impl::type_impl::primitive_impl { +class Int : public Primitive { +public: + // Factory function + /** + * @param spec + * @return A unique pointer to a new `Int` instance with the given type spec. + */ + [[nodiscard]] static auto create(IntSpec spec) -> std::unique_ptr { + return std::make_unique(Int{spec}); + } + + // Methods implementing `Node` + [[nodiscard]] auto serialize_to_str(size_t indentation_level) const + -> ystdlib::error_handling::Result override; + + // Methods + [[nodiscard]] auto get_spec() const -> IntSpec { return m_spec; } + +private: + // Constructor + explicit Int(IntSpec spec) : m_spec{spec} {} + + // Variables + IntSpec m_spec; +}; +} // namespace spider::tdl::parser::ast::node_impl::type_impl::primitive_impl + +#endif // SPIDER_TDL_PARSER_AST_NODE_IMPL_TYPE_IMPL_PRIMITIVE_IMPL_INT_HPP diff --git a/src/spider/tdl/parser/ast/utils.cpp b/src/spider/tdl/parser/ast/utils.cpp index b99cca5bf..e6a006136 100644 --- a/src/spider/tdl/parser/ast/utils.cpp +++ b/src/spider/tdl/parser/ast/utils.cpp @@ -2,6 +2,13 @@ #include #include +#include + +#include + +#include +#include +#include namespace spider::tdl::parser::ast { auto create_indentation(size_t indentation_level) -> std::string { @@ -10,4 +17,30 @@ auto create_indentation(size_t indentation_level) -> std::string { // NOLINTNEXTLINE(modernize-return-braced-init-list) return std::string(indentation_level * 2, ' '); } + +auto serialize_int_spec(IntSpec spec) -> ystdlib::error_handling::Result { + switch (spec) { + case IntSpec::Int8: + return "int8"; + case IntSpec::Int16: + return "int16"; + case IntSpec::Int32: + return "int32"; + case IntSpec::Int64: + return "int64"; + default: + return Node::ErrorCode{Node::ErrorCodeEnum::UnknownTypeSpec}; + } +} + +auto serialize_float_spec(FloatSpec spec) -> ystdlib::error_handling::Result { + switch (spec) { + case FloatSpec::Float: + return "float"; + case FloatSpec::Double: + return "double"; + default: + return Node::ErrorCode{Node::ErrorCodeEnum::UnknownTypeSpec}; + } +} } // namespace spider::tdl::parser::ast diff --git a/src/spider/tdl/parser/ast/utils.hpp b/src/spider/tdl/parser/ast/utils.hpp index 2a52e4a6d..9544837b7 100644 --- a/src/spider/tdl/parser/ast/utils.hpp +++ b/src/spider/tdl/parser/ast/utils.hpp @@ -3,6 +3,13 @@ #include #include +#include + +#include + +#include +#include +#include namespace spider::tdl::parser::ast { /** @@ -12,6 +19,47 @@ namespace spider::tdl::parser::ast { * @return A string containing the specified number of indentation levels. */ [[nodiscard]] auto create_indentation(size_t indentation_level) -> std::string; + +/** + * Serializes an `IntSpec` to a string view. + * @param spec + * @return A result containing a string view representation of `spec` on success, or an error code + * indicating the failure: + * - Node::ErrorCodeEnum::UnknownTypeSpec if the type spec is unrecognized. + */ +[[nodiscard]] auto serialize_int_spec(IntSpec spec) + -> ystdlib::error_handling::Result; + +/** + * Serializes an `FloatSpec` to a string view. + * @param spec + * @return A result containing a string view representation of `spec` on success, or an error code + * indicating the failure: + * - Node::ErrorCodeEnum::UnknownTypeSpec if the type spec is unrecognized. + */ +[[nodiscard]] auto serialize_float_spec(FloatSpec spec) + -> ystdlib::error_handling::Result; + +/** + * Validates that the given node is of the expected type. + * @tparam ExpectedNodeType + * @param node The node to validate. + * @return A result containing void on success, or an error code indicating the failure: + * - Node::ErrorCodeEnum::UnexpectedChildNodeType if the node is not of the expected type. + */ +template +requires std::is_base_of_v +[[nodiscard]] auto validate_child_node_type(Node const* node) + -> ystdlib::error_handling::Result; + +template +requires std::is_base_of_v +auto validate_child_node_type(Node const* node) -> ystdlib::error_handling::Result { + if (nullptr == dynamic_cast(node)) { + return Node::ErrorCode{Node::ErrorCodeEnum::UnexpectedChildNodeType}; + } + return ystdlib::error_handling::success(); +} } // namespace spider::tdl::parser::ast #endif // SPIDER_TDL_PARSER_UTILS_HPP From 1058e9e0641f2c89ac8922cf2839722758ae5f27 Mon Sep 17 00:00:00 2001 From: LinZhihao-723 Date: Thu, 7 Aug 2025 17:59:41 -0400 Subject: [PATCH 14/24] Add unit tests. --- .../type_impl/primitive_impl/Float.cpp | 2 +- .../type_impl/primitive_impl/Int.cpp | 2 +- tests/tdl/test-parser-ast.cpp | 170 ++++++++++++++++++ 3 files changed, 172 insertions(+), 2 deletions(-) diff --git a/src/spider/tdl/parser/ast/node_impl/type_impl/primitive_impl/Float.cpp b/src/spider/tdl/parser/ast/node_impl/type_impl/primitive_impl/Float.cpp index 4b08c4c2e..d433aa4e0 100644 --- a/src/spider/tdl/parser/ast/node_impl/type_impl/primitive_impl/Float.cpp +++ b/src/spider/tdl/parser/ast/node_impl/type_impl/primitive_impl/Float.cpp @@ -12,7 +12,7 @@ namespace spider::tdl::parser::ast::node_impl::type_impl::primitive_impl { auto Float::serialize_to_str(size_t indentation_level) const -> ystdlib::error_handling::Result { return fmt::format( - "{}[Type[Primitive[Float]]]: {}", + "{}[Type[Primitive[Float]]]:{}", create_indentation(indentation_level), YSTDLIB_ERROR_HANDLING_TRYX(serialize_float_spec(m_spec)) ); diff --git a/src/spider/tdl/parser/ast/node_impl/type_impl/primitive_impl/Int.cpp b/src/spider/tdl/parser/ast/node_impl/type_impl/primitive_impl/Int.cpp index f1e2c25a1..26aa853c3 100644 --- a/src/spider/tdl/parser/ast/node_impl/type_impl/primitive_impl/Int.cpp +++ b/src/spider/tdl/parser/ast/node_impl/type_impl/primitive_impl/Int.cpp @@ -12,7 +12,7 @@ namespace spider::tdl::parser::ast::node_impl::type_impl::primitive_impl { auto Int::serialize_to_str(size_t indentation_level) const -> ystdlib::error_handling::Result { return fmt::format( - "{}[Type[Primitive[Int]]]: {}", + "{}[Type[Primitive[Int]]]:{}", create_indentation(indentation_level), YSTDLIB_ERROR_HANDLING_TRYX(serialize_int_spec(m_spec)) ); diff --git a/tests/tdl/test-parser-ast.cpp b/tests/tdl/test-parser-ast.cpp index 00fea8b06..c9de6aa87 100644 --- a/tests/tdl/test-parser-ast.cpp +++ b/tests/tdl/test-parser-ast.cpp @@ -2,17 +2,36 @@ #include #include +#include #include +#include #include +#include +#include #include #include +#include +#include +#include +#include +#include +#include namespace { TEST_CASE("test-ast-node", "[tdl][ast][Node]") { + using spider::tdl::parser::ast::FloatSpec; + 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::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; + using spider::tdl::parser::ast::node_impl::type_impl::primitive_impl::Float; + using spider::tdl::parser::ast::node_impl::type_impl::primitive_impl::Int; + using spider::tdl::parser::ast::serialize_float_spec; + using spider::tdl::parser::ast::serialize_int_spec; using ystdlib::error_handling::Result; SECTION("Identifier") { @@ -30,6 +49,157 @@ TEST_CASE("test-ast-node", "[tdl][ast][Node]") { REQUIRE_FALSE(serialized_result.has_error()); REQUIRE(serialized_result.value() == cSerializedIdentifier); } + + SECTION("Type Int") { + auto const int_spec + = GENERATE(IntSpec::Int8, IntSpec::Int16, IntSpec::Int32, IntSpec::Int64); + auto const serialized_int_spec_result{serialize_int_spec(int_spec)}; + REQUIRE_FALSE(serialized_int_spec_result.has_error()); + + auto const node{Int::create(int_spec)}; + auto const* int_node{dynamic_cast(node.get())}; + REQUIRE(nullptr != int_node); + + REQUIRE(int_node->get_spec() == int_spec); + + constexpr std::string_view cExpectedSerializedResultPrefix{"[Type[Primitive[Int]]]:"}; + auto const serialized_result{int_node->serialize_to_str(0)}; + REQUIRE_FALSE(serialized_result.has_error()); + auto const expected_serialized_result{ + std::string{cExpectedSerializedResultPrefix} + + std::string{serialized_int_spec_result.value()} + }; + REQUIRE(serialized_result.value() == expected_serialized_result); + } + + SECTION("Type Float") { + auto const float_spec = GENERATE(FloatSpec::Float, FloatSpec::Double); + auto const serialized_float_spec_result{serialize_float_spec(float_spec)}; + REQUIRE_FALSE(serialized_float_spec_result.has_error()); + + auto const node{Float::create(float_spec)}; + auto const* float_node{dynamic_cast(node.get())}; + REQUIRE(nullptr != float_node); + + REQUIRE(float_node->get_spec() == float_spec); + + constexpr std::string_view cExpectedSerializedResultPrefix{"[Type[Primitive[Float]]]:"}; + auto const serialized_result{float_node->serialize_to_str(0)}; + REQUIRE_FALSE(serialized_result.has_error()); + auto const expected_serialized_result{ + std::string{cExpectedSerializedResultPrefix} + + std::string{serialized_float_spec_result.value()} + }; + REQUIRE(serialized_result.value() == expected_serialized_result); + } + + SECTION("Type Bool") { + auto const node{Bool::create()}; + auto const* bool_node{dynamic_cast(node.get())}; + REQUIRE(nullptr != bool_node); + + constexpr std::string_view cExpectedSerializedResult{"[Type[Primitive[Bool]]]"}; + auto const serialized_result{bool_node->serialize_to_str(0)}; + REQUIRE_FALSE(serialized_result.has_error()); + REQUIRE(serialized_result.value() == cExpectedSerializedResult); + } + + SECTION("List of Map") { + auto map_result{Map::create(Int::create(IntSpec::Int64), Float::create(FloatSpec::Double))}; + REQUIRE_FALSE(map_result.has_error()); + auto list_result{List::create(std::move(map_result.value()))}; + REQUIRE_FALSE(list_result.has_error()); + auto const* list_node{dynamic_cast(list_result.value().get())}; + REQUIRE(nullptr != list_node); + + REQUIRE(list_node->get_num_children() == 1); + + constexpr std::string_view cExpectedSerializedResult{ + "[Type[Container[List]]]:\n" + " ElementType:\n" + " [Type[Container[Map]]]:\n" + " KeyTpe:\n" + " [Type[Primitive[Int]]]:int64\n" + " ValueType:\n" + " [Type[Primitive[Float]]]:double" + }; + auto const serialized_result{list_node->serialize_to_str(0)}; + REQUIRE_FALSE(serialized_result.has_error()); + REQUIRE(serialized_result.value() == cExpectedSerializedResult); + } + + SECTION("Map of List") { + auto key_list_result{List::create(Int::create(IntSpec::Int8))}; + REQUIRE_FALSE(key_list_result.has_error()); + auto value_list_result{List::create(Float::create(FloatSpec::Float))}; + REQUIRE_FALSE(value_list_result.has_error()); + auto map_result{Map::create( + std::move(key_list_result.value()), + std::move(value_list_result.value()) + )}; + REQUIRE_FALSE(map_result.has_error()); + auto const* map_node{dynamic_cast(map_result.value().get())}; + REQUIRE(nullptr != map_node); + + REQUIRE(map_node->get_num_children() == 2); + + constexpr std::string_view cExpectedSerializedResult{ + "[Type[Container[Map]]]:\n" + " KeyTpe:\n" + " [Type[Container[List]]]:\n" + " ElementType:\n" + " [Type[Primitive[Int]]]:int8\n" + " ValueType:\n" + " [Type[Container[List]]]:\n" + " ElementType:\n" + " [Type[Primitive[Float]]]:float" + }; + auto const serialized_result{map_node->serialize_to_str(0)}; + REQUIRE_FALSE(serialized_result.has_error()); + REQUIRE(serialized_result.value() == cExpectedSerializedResult); + } + + SECTION("Invalid inputs for container type creation") { + constexpr std::string_view cTestName{"test_name"}; + auto list_result{List::create(Identifier::create(std::string{cTestName}))}; + REQUIRE(list_result.has_error()); + REQUIRE(list_result.error() + == Node::ErrorCode{Node::ErrorCodeEnum::UnexpectedChildNodeType}); + + auto invalid_key_type_map_result{ + Map::create(Identifier::create(std::string{cTestName}), Int::create(IntSpec::Int64)) + }; + REQUIRE(invalid_key_type_map_result.has_error()); + REQUIRE(invalid_key_type_map_result.error() + == Node::ErrorCode{Node::ErrorCodeEnum::UnexpectedChildNodeType}); + + auto invalid_value_type_map_result{ + Map::create(Int::create(IntSpec::Int64), Identifier::create(std::string{cTestName})) + }; + REQUIRE(invalid_value_type_map_result.has_error()); + REQUIRE(invalid_value_type_map_result.error() + == Node::ErrorCode{Node::ErrorCodeEnum::UnexpectedChildNodeType}); + } + + SECTION("Unsupported key types in Map") { + // We can't enum all types. Just asserting two types to ensure that the error is propagated + // correctly. + auto unsupported_primitive_key_type_map_result{ + Map::create(Float::create(FloatSpec::Float), Int::create(IntSpec::Int64)) + }; + REQUIRE(unsupported_primitive_key_type_map_result.has_error()); + REQUIRE(unsupported_primitive_key_type_map_result.error() + == Map::ErrorCode{Map::ErrorCodeEnum::UnsupportedKeyType}); + + auto list_result{List::create(Int::create(IntSpec::Int64))}; + REQUIRE_FALSE(list_result.has_error()); + auto unsupported_list_key_type_map_result{ + Map::create(std::move(list_result.value()), Int::create(IntSpec::Int64)) + }; + REQUIRE(unsupported_list_key_type_map_result.has_error()); + REQUIRE(unsupported_list_key_type_map_result.error() + == Map::ErrorCode{Map::ErrorCodeEnum::UnsupportedKeyType}); + } } } // namespace From 357df42b691164a0e05514b52e1cbd2619cbd11e Mon Sep 17 00:00:00 2001 From: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> Date: Thu, 7 Aug 2025 18:42:22 -0400 Subject: [PATCH 15/24] Update src/spider/CMakeLists.txt Co-authored-by: sitaowang1998 --- src/spider/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spider/CMakeLists.txt b/src/spider/CMakeLists.txt index db95d034f..89b0b7b28 100644 --- a/src/spider/CMakeLists.txt +++ b/src/spider/CMakeLists.txt @@ -219,8 +219,8 @@ target_include_directories(spider_tdl PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/..) target_link_libraries( spider_tdl PUBLIC - ystdlib::error_handling fmt::fmt + ystdlib::error_handling ) add_library(spider::tdl ALIAS spider_tdl) From 625c8460c64ae70c0ce86395f69ab0ae4b493fa6 Mon Sep 17 00:00:00 2001 From: LinZhihao-723 Date: Thu, 7 Aug 2025 18:42:43 -0400 Subject: [PATCH 16/24] Fix the header guard. --- src/spider/tdl/parser/ast/utils.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/spider/tdl/parser/ast/utils.hpp b/src/spider/tdl/parser/ast/utils.hpp index 2a52e4a6d..da2fac0d9 100644 --- a/src/spider/tdl/parser/ast/utils.hpp +++ b/src/spider/tdl/parser/ast/utils.hpp @@ -1,5 +1,5 @@ -#ifndef SPIDER_TDL_PARSER_UTILS_HPP -#define SPIDER_TDL_PARSER_UTILS_HPP +#ifndef SPIDER_TDL_PARSER_AST_UTILS_HPP +#define SPIDER_TDL_PARSER_AST_UTILS_HPP #include #include @@ -14,4 +14,4 @@ namespace spider::tdl::parser::ast { [[nodiscard]] auto create_indentation(size_t indentation_level) -> std::string; } // namespace spider::tdl::parser::ast -#endif // SPIDER_TDL_PARSER_UTILS_HPP +#endif // SPIDER_TDL_PARSER_AST_UTILS_HPP From 744ccf9535c1745b947878a2b1575091e989c34f Mon Sep 17 00:00:00 2001 From: LinZhihao-723 Date: Thu, 7 Aug 2025 18:45:22 -0400 Subject: [PATCH 17/24] Fix typo. --- .../tdl/parser/ast/node_impl/type_impl/container_impl/Map.cpp | 2 +- tests/tdl/test-parser-ast.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/spider/tdl/parser/ast/node_impl/type_impl/container_impl/Map.cpp b/src/spider/tdl/parser/ast/node_impl/type_impl/container_impl/Map.cpp index 536fc5717..588945b48 100644 --- a/src/spider/tdl/parser/ast/node_impl/type_impl/container_impl/Map.cpp +++ b/src/spider/tdl/parser/ast/node_impl/type_impl/container_impl/Map.cpp @@ -84,7 +84,7 @@ auto Map::create(std::unique_ptr key_type, std::unique_ptr value_typ auto Map::serialize_to_str(size_t indentation_level) const -> ystdlib::error_handling::Result { return fmt::format( - "{}[Type[Container[Map]]]:\n{}KeyTpe:\n{}\n{}ValueType:\n{}", + "{}[Type[Container[Map]]]:\n{}KeyType:\n{}\n{}ValueType:\n{}", create_indentation(indentation_level), create_indentation(indentation_level + 1), YSTDLIB_ERROR_HANDLING_TRYX(get_key_type()->serialize_to_str(indentation_level + 2)), diff --git a/tests/tdl/test-parser-ast.cpp b/tests/tdl/test-parser-ast.cpp index c9de6aa87..8541a5143 100644 --- a/tests/tdl/test-parser-ast.cpp +++ b/tests/tdl/test-parser-ast.cpp @@ -118,7 +118,7 @@ TEST_CASE("test-ast-node", "[tdl][ast][Node]") { "[Type[Container[List]]]:\n" " ElementType:\n" " [Type[Container[Map]]]:\n" - " KeyTpe:\n" + " KeyType:\n" " [Type[Primitive[Int]]]:int64\n" " ValueType:\n" " [Type[Primitive[Float]]]:double" @@ -145,7 +145,7 @@ TEST_CASE("test-ast-node", "[tdl][ast][Node]") { constexpr std::string_view cExpectedSerializedResult{ "[Type[Container[Map]]]:\n" - " KeyTpe:\n" + " KeyType:\n" " [Type[Container[List]]]:\n" " ElementType:\n" " [Type[Primitive[Int]]]:int8\n" From e6283a52e864ccb000a1a710b6fc519e9c756eb3 Mon Sep 17 00:00:00 2001 From: LinZhihao-723 Date: Thu, 7 Aug 2025 19:35:43 -0400 Subject: [PATCH 18/24] Fix the docstring. --- .../parser/ast/node_impl/type_impl/container_impl/List.hpp | 4 ++-- .../tdl/parser/ast/node_impl/type_impl/container_impl/Map.hpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/spider/tdl/parser/ast/node_impl/type_impl/container_impl/List.hpp b/src/spider/tdl/parser/ast/node_impl/type_impl/container_impl/List.hpp index 9da0404ec..94d49d4cc 100644 --- a/src/spider/tdl/parser/ast/node_impl/type_impl/container_impl/List.hpp +++ b/src/spider/tdl/parser/ast/node_impl/type_impl/container_impl/List.hpp @@ -17,8 +17,8 @@ class List : public Container { // Factory function /** * @param element_type The type of elements in the list. - * @return A result containing a unique pointer to a new `List` instance with the given name on - * success, or an error code indicating the failure: + * @return A result containing a unique pointer to a new `List` instance with the given element + * type on success, or an error code indicating the failure: * - Forwards `validate_child_node_type`'s return values. */ [[nodiscard]] static auto create(std::unique_ptr element_type) diff --git a/src/spider/tdl/parser/ast/node_impl/type_impl/container_impl/Map.hpp b/src/spider/tdl/parser/ast/node_impl/type_impl/container_impl/Map.hpp index 621ce4335..86c74d9c7 100644 --- a/src/spider/tdl/parser/ast/node_impl/type_impl/container_impl/Map.hpp +++ b/src/spider/tdl/parser/ast/node_impl/type_impl/container_impl/Map.hpp @@ -27,8 +27,8 @@ class Map : public Container { /** * @param key_type * @param value_type - * @return A result containing a unique pointer to a new `Map` instance with the given name on - * success, or an error code indicating the failure: + * @return A result containing a unique pointer to a new `Map` instance with the given key and + * value types on success, or an error code indicating the failure: * - Map::ErrorCodeEnum::UnsupportedKeyType if the `key_type` is not supported. * - Forwards `validate_child_node_type`'s return values. */ From 0bea88e0c8fe0d93561fe30f0371e5fd80ef2016 Mon Sep 17 00:00:00 2001 From: LinZhihao-723 Date: Thu, 7 Aug 2025 19:37:01 -0400 Subject: [PATCH 19/24] WIP. --- .../tdl/parser/ast/node_impl/NamedVar.cpp | 5 +++ .../tdl/parser/ast/node_impl/NamedVar.hpp | 37 +++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 src/spider/tdl/parser/ast/node_impl/NamedVar.cpp create mode 100644 src/spider/tdl/parser/ast/node_impl/NamedVar.hpp 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..47bd26240 --- /dev/null +++ b/src/spider/tdl/parser/ast/node_impl/NamedVar.cpp @@ -0,0 +1,5 @@ +// +// Created by pleia on 8/7/2025. +// + +#include "NamedVar.hpp" 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..2b8de83ba --- /dev/null +++ b/src/spider/tdl/parser/ast/node_impl/NamedVar.hpp @@ -0,0 +1,37 @@ +#ifndef SPIDER_TDL_PARSER_AST_NODE_IMPL_NAMEDVAR_HPP +#define SPIDER_TDL_PARSER_AST_NODE_IMPL_NAMEDVAR_HPP + +#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: + * - Map::ErrorCodeEnum::UnsupportedKeyType if the `key_type` is not supported. + * - Forwards `validate_child_node_type`'s return values. + */ + [[nodiscard]] static auto create(std::unique_ptr id, std::unique_ptr type) + -> ystdlib::error_handling::Result>; + +private: + // Constructor + NamedVar() = default; +}; +} // namespace spider::tdl::parser::ast::node_impl + +#endif // SPIDER_TDL_PARSER_AST_NODE_IMPL_NAMEDVAR_HPP From 1bfaf5ac0202cf3375678c5ac2d678c11dcbbf9d Mon Sep 17 00:00:00 2001 From: LinZhihao-723 Date: Fri, 8 Aug 2025 12:16:21 -0400 Subject: [PATCH 20/24] Apply code review comments. --- .../type_impl/container_impl/Map.cpp | 10 +++-- .../type_impl/container_impl/Map.hpp | 2 +- tests/tdl/test-parser-ast.cpp | 40 +++++++++---------- 3 files changed, 27 insertions(+), 25 deletions(-) diff --git a/src/spider/tdl/parser/ast/node_impl/type_impl/container_impl/Map.cpp b/src/spider/tdl/parser/ast/node_impl/type_impl/container_impl/Map.cpp index 588945b48..22bac7482 100644 --- a/src/spider/tdl/parser/ast/node_impl/type_impl/container_impl/Map.cpp +++ b/src/spider/tdl/parser/ast/node_impl/type_impl/container_impl/Map.cpp @@ -71,13 +71,15 @@ auto Map::create(std::unique_ptr key_type, std::unique_ptr value_typ YSTDLIB_ERROR_HANDLING_TRYV(validate_child_node_type(key_type.get())); YSTDLIB_ERROR_HANDLING_TRYV(validate_child_node_type(value_type.get())); + // `key_type` has already been validated to be `Type` object. + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-static-cast-downcast) + if (false == is_supported_key_type(static_cast(key_type.get()))) { + return ErrorCode{ErrorCodeEnum::UnsupportedKeyType}; + } + auto map{std::make_unique(Map{})}; YSTDLIB_ERROR_HANDLING_TRYV(map->add_child(std::move(key_type))); YSTDLIB_ERROR_HANDLING_TRYV(map->add_child(std::move(value_type))); - - if (false == is_supported_key_type(map->get_key_type())) { - return Map::ErrorCode{Map::ErrorCodeEnum::UnsupportedKeyType}; - } return map; } diff --git a/src/spider/tdl/parser/ast/node_impl/type_impl/container_impl/Map.hpp b/src/spider/tdl/parser/ast/node_impl/type_impl/container_impl/Map.hpp index 86c74d9c7..25040c552 100644 --- a/src/spider/tdl/parser/ast/node_impl/type_impl/container_impl/Map.hpp +++ b/src/spider/tdl/parser/ast/node_impl/type_impl/container_impl/Map.hpp @@ -48,7 +48,7 @@ class Map : public Container { } [[nodiscard]] auto get_value_type() const -> Type const* { - // The factory function ensures that the first child is of type `Type`. + // 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)); } diff --git a/tests/tdl/test-parser-ast.cpp b/tests/tdl/test-parser-ast.cpp index 8541a5143..d949676e2 100644 --- a/tests/tdl/test-parser-ast.cpp +++ b/tests/tdl/test-parser-ast.cpp @@ -17,7 +17,6 @@ #include #include #include -#include namespace { TEST_CASE("test-ast-node", "[tdl][ast][Node]") { @@ -30,8 +29,6 @@ TEST_CASE("test-ast-node", "[tdl][ast][Node]") { using spider::tdl::parser::ast::node_impl::type_impl::primitive_impl::Bool; using spider::tdl::parser::ast::node_impl::type_impl::primitive_impl::Float; using spider::tdl::parser::ast::node_impl::type_impl::primitive_impl::Int; - using spider::tdl::parser::ast::serialize_float_spec; - using spider::tdl::parser::ast::serialize_int_spec; using ystdlib::error_handling::Result; SECTION("Identifier") { @@ -51,45 +48,46 @@ TEST_CASE("test-ast-node", "[tdl][ast][Node]") { } SECTION("Type Int") { - auto const int_spec - = GENERATE(IntSpec::Int8, IntSpec::Int16, IntSpec::Int32, IntSpec::Int64); - auto const serialized_int_spec_result{serialize_int_spec(int_spec)}; - REQUIRE_FALSE(serialized_int_spec_result.has_error()); + auto const [int_spec, expected_serialized_result] = GENERATE( + std::make_pair(IntSpec::Int8, std::string_view{"[Type[Primitive[Int]]]:int8"}), + std::make_pair(IntSpec::Int16, std::string_view{"[Type[Primitive[Int]]]:int16"}), + std::make_pair(IntSpec::Int32, std::string_view{"[Type[Primitive[Int]]]:int32"}), + std::make_pair(IntSpec::Int64, std::string_view{"[Type[Primitive[Int]]]:int64"}) + ); auto const node{Int::create(int_spec)}; auto const* int_node{dynamic_cast(node.get())}; REQUIRE(nullptr != int_node); REQUIRE(int_node->get_spec() == int_spec); + REQUIRE(int_node->get_num_children() == 0); - constexpr std::string_view cExpectedSerializedResultPrefix{"[Type[Primitive[Int]]]:"}; auto const serialized_result{int_node->serialize_to_str(0)}; REQUIRE_FALSE(serialized_result.has_error()); - auto const expected_serialized_result{ - std::string{cExpectedSerializedResultPrefix} - + std::string{serialized_int_spec_result.value()} - }; REQUIRE(serialized_result.value() == expected_serialized_result); } SECTION("Type Float") { - auto const float_spec = GENERATE(FloatSpec::Float, FloatSpec::Double); - auto const serialized_float_spec_result{serialize_float_spec(float_spec)}; - REQUIRE_FALSE(serialized_float_spec_result.has_error()); + auto const [float_spec, expected_serialized_result] = GENERATE( + std::make_pair( + FloatSpec::Float, + std::string_view{"[Type[Primitive[Float]]]:float"} + ), + std::make_pair( + FloatSpec::Double, + std::string_view{"[Type[Primitive[Float]]]:double"} + ) + ); auto const node{Float::create(float_spec)}; auto const* float_node{dynamic_cast(node.get())}; REQUIRE(nullptr != float_node); REQUIRE(float_node->get_spec() == float_spec); + REQUIRE(float_node->get_num_children() == 0); - constexpr std::string_view cExpectedSerializedResultPrefix{"[Type[Primitive[Float]]]:"}; auto const serialized_result{float_node->serialize_to_str(0)}; REQUIRE_FALSE(serialized_result.has_error()); - auto const expected_serialized_result{ - std::string{cExpectedSerializedResultPrefix} - + std::string{serialized_float_spec_result.value()} - }; REQUIRE(serialized_result.value() == expected_serialized_result); } @@ -98,6 +96,8 @@ TEST_CASE("test-ast-node", "[tdl][ast][Node]") { auto const* bool_node{dynamic_cast(node.get())}; REQUIRE(nullptr != bool_node); + REQUIRE(bool_node->get_num_children() == 0); + constexpr std::string_view cExpectedSerializedResult{"[Type[Primitive[Bool]]]"}; auto const serialized_result{bool_node->serialize_to_str(0)}; REQUIRE_FALSE(serialized_result.has_error()); From 1bca37543b0fda65f49175becf78a09f05a56f0e Mon Sep 17 00:00:00 2001 From: LinZhihao-723 Date: Fri, 8 Aug 2025 14:32:07 -0400 Subject: [PATCH 21/24] Implement NamedVar --- src/spider/CMakeLists.txt | 2 + .../tdl/parser/ast/node_impl/NamedVar.cpp | 40 +++++++++++++++++-- .../tdl/parser/ast/node_impl/NamedVar.hpp | 21 +++++++++- 3 files changed, 57 insertions(+), 6 deletions(-) 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/NamedVar.cpp b/src/spider/tdl/parser/ast/node_impl/NamedVar.cpp index 47bd26240..22dc1ff00 100644 --- a/src/spider/tdl/parser/ast/node_impl/NamedVar.cpp +++ b/src/spider/tdl/parser/ast/node_impl/NamedVar.cpp @@ -1,5 +1,37 @@ -// -// Created by pleia on 8/7/2025. -// - #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{}\n{}", + create_indentation(indentation_level), + YSTDLIB_ERROR_HANDLING_TRYX(get_id()->serialize_to_str(indentation_level + 1)), + YSTDLIB_ERROR_HANDLING_TRYX(get_type()->serialize_to_str(indentation_level + 1)) + ); +} +} // 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 index 2b8de83ba..1a9cf998c 100644 --- a/src/spider/tdl/parser/ast/node_impl/NamedVar.hpp +++ b/src/spider/tdl/parser/ast/node_impl/NamedVar.hpp @@ -1,9 +1,10 @@ #ifndef SPIDER_TDL_PARSER_AST_NODE_IMPL_NAMEDVAR_HPP #define SPIDER_TDL_PARSER_AST_NODE_IMPL_NAMEDVAR_HPP +#include #include +#include -#include #include #include @@ -22,12 +23,28 @@ class NamedVar : public Node { * @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: - * - Map::ErrorCodeEnum::UnsupportedKeyType if the `key_type` is not supported. * - 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 first child is of type `Type`. + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-static-cast-downcast) + return static_cast(get_child_unsafe(1)); + } + private: // Constructor NamedVar() = default; From e866db16686e37ad8d9cb8bf1def1fe350361db5 Mon Sep 17 00:00:00 2001 From: LinZhihao-723 Date: Fri, 8 Aug 2025 14:52:45 -0400 Subject: [PATCH 22/24] Add unit tests --- .../tdl/parser/ast/node_impl/Identifier.cpp | 2 +- .../tdl/parser/ast/node_impl/NamedVar.cpp | 10 +++--- tests/tdl/test-parser-ast.cpp | 33 ++++++++++++++++++- 3 files changed, 39 insertions(+), 6 deletions(-) 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 index 22dc1ff00..c988b0f14 100644 --- a/src/spider/tdl/parser/ast/node_impl/NamedVar.cpp +++ b/src/spider/tdl/parser/ast/node_impl/NamedVar.cpp @@ -8,10 +8,10 @@ #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) @@ -28,10 +28,12 @@ auto NamedVar::create(std::unique_ptr id, std::unique_ptr type) auto NamedVar::serialize_to_str(size_t indentation_level) const -> ystdlib::error_handling::Result { return fmt::format( - "{}[NamedVar]:\n{}\n{}", + "{}[NamedVar]:\n{}Id:\n{}\n{}Type:\n{}", create_indentation(indentation_level), - YSTDLIB_ERROR_HANDLING_TRYX(get_id()->serialize_to_str(indentation_level + 1)), - YSTDLIB_ERROR_HANDLING_TRYX(get_type()->serialize_to_str(indentation_level + 1)) + 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/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 From 7a2e7b38314381f1dd4035db3010a786b712df07 Mon Sep 17 00:00:00 2001 From: LinZhihao-723 Date: Fri, 8 Aug 2025 15:14:02 -0400 Subject: [PATCH 23/24] Fix unit tests --- tests/tdl/test-parser-ast.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tdl/test-parser-ast.cpp b/tests/tdl/test-parser-ast.cpp index cb7413e87..94df70457 100644 --- a/tests/tdl/test-parser-ast.cpp +++ b/tests/tdl/test-parser-ast.cpp @@ -35,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())}; From 7216617e2ee9a5b6d1901e5a5db8f0fca934e1d2 Mon Sep 17 00:00:00 2001 From: Lin Zhihao <59785146+LinZhihao-723@users.noreply.github.com> Date: Fri, 8 Aug 2025 15:38:16 -0400 Subject: [PATCH 24/24] Update src/spider/tdl/parser/ast/node_impl/NamedVar.hpp Co-authored-by: sitaowang1998 --- src/spider/tdl/parser/ast/node_impl/NamedVar.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spider/tdl/parser/ast/node_impl/NamedVar.hpp b/src/spider/tdl/parser/ast/node_impl/NamedVar.hpp index 1a9cf998c..deed577a2 100644 --- a/src/spider/tdl/parser/ast/node_impl/NamedVar.hpp +++ b/src/spider/tdl/parser/ast/node_impl/NamedVar.hpp @@ -40,7 +40,7 @@ class NamedVar : public Node { } [[nodiscard]] auto get_type() const noexcept -> Type const* { - // The factory function ensures that the first child is of type `Type`. + // 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)); }