/// sforth, an implementation of forth
/// Copyright (C) 2024  Clyne Sullivan <clyne@bitgloo.com>
///
/// This program is free software: you can redistribute it and/or modify it
/// under the terms of the GNU General Public License as published by the Free
/// Software Foundation, either version 3 of the License, or (at your option)
/// any later version.
///
/// This program is distributed in the hope that it will be useful, but WITHOUT
/// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
/// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
/// more details.
///
/// You should have received a copy of the GNU General Public License along
/// with this program.  If not, see <http://www.gnu.org/licenses/>.

#include "forth.hpp"

#include <array>
#include <fstream>
#include <iostream>
#include <span>
#include <string>

static std::array<forth::cell, 1024> dict;
static auto fth = new (dict.data()) forth;

static bool parse_stream(forth *, std::istream&, bool say_okay = false);

int main(int argc, const char *argv[])
{
    std::span args (argv + 1, argc - 1);

    forth::initialize<&fth>(dict.end());
    fth->add(".", [](auto) { std::cout << fth->pop() << ' '; });
    fth->add("emit", [](auto) { std::cout << static_cast<char>(fth->pop()); });

    for (auto arg : args) {
        if (std::ifstream file {arg}; parse_stream(fth, file))
            return 0;
    }

    parse_stream(fth, std::cin, true);
}

bool parse_stream(forth *fth, std::istream& str, bool say_okay)
{
    std::string line;

    while (str.good()) {
        std::getline(str, line);
        if (!line.empty()) {
            if (line == "bye")
                return true;

            try {
                fth->parse_line(line);
            } catch (forth::error e) {
                std::cerr << fth->error_string(e);
                continue;
            }
        }

        if (say_okay)
            std::cout << (fth->compiling ? "compiled" : "ok") << std::endl;
    }

    return false;
}