Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/spider/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ add_library(spider::spider ALIAS spider_client)

set(SPIDER_TDL_SHARED_SOURCES
tdl/parser/ast/Node.cpp
tdl/parser/ast/node_impl/Function.cpp
tdl/parser/ast/node_impl/Identifier.cpp
tdl/parser/ast/node_impl/NamedVar.cpp
tdl/parser/ast/node_impl/StructSpec.cpp
Expand All @@ -216,6 +217,7 @@ 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/Function.hpp
tdl/parser/ast/node_impl/Identifier.hpp
tdl/parser/ast/node_impl/NamedVar.hpp
tdl/parser/ast/node_impl/StructSpec.hpp
Expand Down
123 changes: 123 additions & 0 deletions src/spider/tdl/parser/ast/node_impl/Function.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#include "Function.hpp"

#include <cstddef>
#include <memory>
#include <string>
#include <string_view>
#include <utility>
#include <vector>

#include <absl/container/flat_hash_set.h>
#include <fmt/format.h>
#include <fmt/ranges.h>
#include <ystdlib/error_handling/ErrorCode.hpp>
#include <ystdlib/error_handling/Result.hpp>

#include <spider/tdl/parser/ast/Node.hpp>
#include <spider/tdl/parser/ast/node_impl/Identifier.hpp>
#include <spider/tdl/parser/ast/node_impl/NamedVar.hpp>
#include <spider/tdl/parser/ast/node_impl/Type.hpp>
#include <spider/tdl/parser/ast/utils.hpp>

using spider::tdl::parser::ast::node_impl::Function;
using FunctionErrorCodeCategory = ystdlib::error_handling::ErrorCategory<Function::ErrorCodeEnum>;

template <>
auto FunctionErrorCodeCategory::name() const noexcept -> char const* {
return "spider::tdl::parser::ast::node_impl::Function";
}

template <>
auto FunctionErrorCodeCategory::message(Function::ErrorCodeEnum error_enum) const -> std::string {
switch (error_enum) {
case Function::ErrorCodeEnum::DuplicatedParamName:
return "The parameters have duplicated names.";
default:
return "Unknown error code enum";
}
}

namespace spider::tdl::parser::ast::node_impl {
auto Function::create(
std::unique_ptr<Node> name,
std::unique_ptr<Node> return_type,
std::vector<std::unique_ptr<Node>> params
) -> ystdlib::error_handling::Result<std::unique_ptr<Node>> {
YSTDLIB_ERROR_HANDLING_TRYV(validate_child_node_type<Identifier>(name.get()));

bool const has_return{nullptr != return_type};
if (has_return) {
YSTDLIB_ERROR_HANDLING_TRYV(validate_child_node_type<Type>(return_type.get()));
}

absl::flat_hash_set<std::string_view> param_names;
for (auto const& param : params) {
YSTDLIB_ERROR_HANDLING_TRYV(validate_child_node_type<NamedVar>(param.get()));
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-static-cast-downcast)
auto const param_name{static_cast<NamedVar const&>(*param).get_id()->get_name()};
if (param_names.contains(param_name)) {
return ErrorCode{ErrorCodeEnum::DuplicatedParamName};
}
param_names.emplace(param_name);
}

auto function{std::make_unique<Function>(Function{has_return})};
YSTDLIB_ERROR_HANDLING_TRYV(function->add_child(std::move(name)));
if (has_return) {
YSTDLIB_ERROR_HANDLING_TRYV(function->add_child(std::move(return_type)));
}
for (auto& param : params) {
YSTDLIB_ERROR_HANDLING_TRYV(function->add_child(std::move(param)));
}
return function;
}

auto Function::serialize_to_str(size_t indentation_level) const
-> ystdlib::error_handling::Result<std::string> {
std::vector<std::string> serialized_params;
YSTDLIB_ERROR_HANDLING_TRYV(
visit_params([&](NamedVar const& param) -> ystdlib::error_handling::Result<void> {
serialized_params.emplace_back(
fmt::format(
"{}Params[{}]:\n{}",
create_indentation(indentation_level + 1),
serialized_params.size(),
YSTDLIB_ERROR_HANDLING_TRYX(
param.serialize_to_str(indentation_level + 2)
)
)
);
return ystdlib::error_handling::success();
})
);

std::string const serialized_return_type{
has_return() ? YSTDLIB_ERROR_HANDLING_TRYX(
get_return_type()->serialize_to_str(indentation_level + 2)
)
: fmt::format("{}void", create_indentation(indentation_level + 2))
};

if (false == serialized_params.empty()) {
return fmt::format(
"{}[Function]:\n{}Name:{}\n{}Return:\n{}\n{}",
create_indentation(indentation_level),
create_indentation(indentation_level + 1),
get_name(),
create_indentation(indentation_level + 1),
serialized_return_type,
fmt::join(serialized_params, "\n")
);
}

return fmt::format(
"{}[Function]:\n{}Name:{}\n{}Return:\n{}\n{}No Params",
create_indentation(indentation_level),
create_indentation(indentation_level + 1),
get_name(),
create_indentation(indentation_level + 1),
serialized_return_type,
create_indentation(indentation_level + 1)
);
}
} // namespace spider::tdl::parser::ast::node_impl
120 changes: 120 additions & 0 deletions src/spider/tdl/parser/ast/node_impl/Function.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
#ifndef SPIDER_TDL_PARSER_AST_NODE_IMPL_FUNCTION_HPP
#define SPIDER_TDL_PARSER_AST_NODE_IMPL_FUNCTION_HPP

#include <cstddef>
#include <cstdint>
#include <memory>
#include <string>
#include <string_view>
#include <type_traits>
#include <vector>

#include <ystdlib/error_handling/ErrorCode.hpp>
#include <ystdlib/error_handling/Result.hpp>

#include <spider/tdl/parser/ast/Node.hpp>
#include <spider/tdl/parser/ast/node_impl/Identifier.hpp>
#include <spider/tdl/parser/ast/node_impl/NamedVar.hpp>
#include <spider/tdl/parser/ast/node_impl/Type.hpp>

namespace spider::tdl::parser::ast::node_impl {
class Function : public Node {
public:
// Types
enum class ErrorCodeEnum : uint8_t {
DuplicatedParamName = 1,
};

using ErrorCode = ystdlib::error_handling::ErrorCode<ErrorCodeEnum>;

// Factory function
/**
* @param name
* @param return_type
* @param params
* @return A result containing a unique pointer to a new `Function` instance with the given
* name, return type, and parameters on success, or an error code indicating the failure:
* - ErrorCodeEnum::DuplicatedParamName if `params` contains duplicated parameter names.
* - Forwards `validate_child_node_type`'s return values.
*/
[[nodiscard]] static auto create(
std::unique_ptr<Node> name,
std::unique_ptr<Node> return_type,
std::vector<std::unique_ptr<Node>> params
) -> ystdlib::error_handling::Result<std::unique_ptr<Node>>;

// Methods implementing `Node`
[[nodiscard]] auto serialize_to_str(size_t indentation_level) const
-> ystdlib::error_handling::Result<std::string> override;

// Methods
[[nodiscard]] auto has_return() const noexcept -> bool { return m_has_return; }

[[nodiscard]] auto get_name() const noexcept -> std::string_view {
// The factory function ensures that the first child is of type `Identifier`.
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-static-cast-downcast)
return static_cast<Identifier const*>(get_child_unsafe(0))->get_name();
}

/**
* @return The return type of the function, or nullptr if the function doesn't have a return.
*/
[[nodiscard]] auto get_return_type() const noexcept -> Type const* {
if (false == m_has_return) {
return nullptr;
}
// The factory function ensures that the second child is of type `Type`, if not nullptr.
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-static-cast-downcast)
return static_cast<Type const*>(get_child_unsafe(1));
}

[[nodiscard]] auto get_num_params() const noexcept -> size_t {
return get_num_children() - get_num_non_param_children();
}

/**
* Visits parameters.
* @tparam ParamVisitor
* @param visitor
* @return A void result on success, or an error code indicating the failure:
* - Forwards `visitor`'s return values.
*/
template <typename ParamVisitor>
requires(std::is_invocable_r_v<
ystdlib::error_handling::Result<void>,
ParamVisitor,
NamedVar const&>)
[[nodiscard]] auto visit_params(ParamVisitor visitor) const
-> ystdlib::error_handling::Result<void> {
for (size_t child_idx{get_num_non_param_children()}; child_idx < get_num_children();
++child_idx)
{
// The factory function ensures that all the child nodes are `NamedVar` except the first
// one.
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-static-cast-downcast)
YSTDLIB_ERROR_HANDLING_TRYV(
visitor(static_cast<NamedVar const&>(*get_child_unsafe(child_idx)))
);
}
return ystdlib::error_handling::success();
}

private:
// Constructor
explicit Function(bool has_return) : m_has_return{has_return} {}

// Methods
[[nodiscard]] auto get_num_non_param_children() const noexcept -> size_t {
return m_has_return ? 2 : 1;
}

// Variables
bool m_has_return;
};
} // namespace spider::tdl::parser::ast::node_impl

YSTDLIB_ERROR_HANDLING_MARK_AS_ERROR_CODE_ENUM(
spider::tdl::parser::ast::node_impl::Function::ErrorCodeEnum
);

#endif // SPIDER_TDL_PARSER_AST_NODE_IMPL_FUNCTION_HPP
Loading