#pragma once
#ifndef RE_H
#define RE_H

#include "Lexesis/automata.h"

#include <memory>
#include <stdexcept>

namespace lxs {
    class RE
    {
        public:
            virtual ~RE() {}
            virtual State toENFA(ENFA& enfa, State attach) = 0;
            virtual std::string toRe() = 0;
    };

    class EmptyRE : public RE
    {
        public:
            EmptyRE() {}
            ~EmptyRE() {}
            virtual State toENFA(ENFA& enfa, State attach);
            virtual std::string toRe();
    };

    class EpsilonRE : public RE
    {
        public:
            EpsilonRE() {}
            ~EpsilonRE() {}
            virtual State toENFA(ENFA& enfa, State attach);
            virtual std::string toRe();
    };

    class SingleRE : public RE
    {
        public:
            SingleRE(char c) : c(c) {}
            ~SingleRE() {}
            virtual State toENFA(ENFA& enfa, State attach);
            virtual std::string toRe();

            char c;
    };

    class ConcatRE : public RE
    {
        public:
            ConcatRE(std::shared_ptr<RE> e, std::shared_ptr<RE> f) : e(e), f(f) {}
            ~ConcatRE() {}
            virtual State toENFA(ENFA& enfa, State attach);
            virtual std::string toRe();

            std::shared_ptr<RE> e, f;
    };

    class StarRE : public RE
    {
        public:
            StarRE(std::shared_ptr<RE> e) : e(e) {}
            ~StarRE() {}
            virtual State toENFA(ENFA& enfa, State attach);
            virtual std::string toRe();

            std::shared_ptr<RE> e;
    };

    class PlusRE : public RE
    {
        public:
            PlusRE(std::shared_ptr<RE> e, std::shared_ptr<RE> f) : e(e), f(f) {}
            ~PlusRE() {}
            virtual State toENFA(ENFA& enfa, State attach);
            virtual std::string toRe();

            std::shared_ptr<RE> e, f;
    };

    std::shared_ptr<RE> parseRE(const std::string& input);

    class SyntaxError : public std::runtime_error
    {
        public:
            SyntaxError(const char* w) : std::runtime_error(w) {}
    };

} //namespace lxs

#endif //RE_H
