BareGit
#ifndef MACRODOWN_NODES_H
#define MACRODOWN_NODES_H

#include <string>
#include <vector>
#include <memory>
#include <variant>

namespace macrodown
{

struct Node; // Forward declaration

struct Text
{
    std::string content;
};

struct Macro
{
    std::string name;
    std::vector<std::unique_ptr<Node>> arguments;
    bool is_special = false;
};

struct Group
{
    std::vector<std::unique_ptr<Node>> children;

    void addChild(std::unique_ptr<Node> node);
};

struct Node
{
    using Data = std::variant<Text, Macro, Group>;
    Data data;

    Node(Text t) : data(std::move(t)) {}
    Node(Macro m) : data(std::move(m)) {}
    Node(Group g) : data(std::move(g)) {}

    // Call function on each node in the tree. Callback function takes
    // const Node& as argument.
    template<typename Callback>
    void forEach(Callback f) const
    {
        f(*this);
        if(std::holds_alternative<Group>(data))
        {
            for(const std::unique_ptr<Node>& child:
                    std::get<Group>(data).children)
            {
                child->forEach(f);
            }
        }
        else if(std::holds_alternative<Macro>(data))
        {
            for(const std::unique_ptr<Node>& arg:
                    std::get<Macro>(data).arguments)
            {
                arg->forEach(f);
            }
        }
    }
};

// Inline implementation to avoid circular dependency issues in headers
inline void Group::addChild(std::unique_ptr<Node> node)
{
    children.push_back(std::move(node));
}

} // namespace macrodown

#endif // MACRODOWN_NODES_H