#ifndef MCALC_NODE_H
#define MCALC_NODE_H

#include <optional>
#include <string>
#include <unordered_set>
#include <memory>
#include <memory_resource>

struct State;

struct Node {
    enum class type {
        NUM,
        VAR,
        NEG,
        PLUS,
        MINUS,
        MUL,
        DIV,
        INVALID
    } ty = type::INVALID;
    double num = 0;
    std::string var{};
    std::unique_ptr<Node> a{}, b{};

    void used_vars(std::unordered_set<std::string>*) const;
    std::optional<double> eval(State*) const;
};

using parser_var_ty = std::variant<double, std::string, Node*>;

template<Node::type ty>
Node *new_node(const parser_var_ty& v) {
    auto *node = new Node { .ty = ty };
    if constexpr (ty == Node::type::NUM)
        node->num = std::get<double>(v);
    else if constexpr (ty == Node::type::VAR)
        node->var = std::get<std::string>(v);
    else
        node->a.reset(std::get<Node*>(v));
    return node;
}

template<Node::type ty>
Node *new_node(const parser_var_ty& a, const parser_var_ty& b) {
    auto *node = new Node { .ty = ty };
    node->a.reset(std::get<Node*>(a));
    node->b.reset(std::get<Node*>(b));
    return node;
}

#endif //MCALC_NODE_H
