/*
 *  A utilitity for building various tables and specializations for the
 *  KJS Frostbyte bytecode
 *
 *  Copyright (C) 2007, 2008 Maks Orlovich (maksim@kde.org)
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library 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
 *  Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public License
 *  along with this library; see the file COPYING.LIB.  If not, write to
 *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 *  Boston, MA 02110-1301, USA.
 *
 */

#include "tablebuilder.h"

#include <fstream>

using std::ifstream;
using std::ofstream;
using std::string;

static bool stringEndsWith(string base, string suffix)
{
    if (base.length() < suffix.length())
        return false;
    return base.substr(base.length() - suffix.length()) == suffix;
}

struct FileTemplate
{
    FileTemplate(string inFileName, string outFileName):
        inFileName(inFileName), outFileName(outFileName)
    {
        isOK  = true;
        lines = 0;

        in.open(inFileName.c_str());
        if (in.fail()) {
            std::cerr << "Unable to open:" << inFileName << "\n";
            isOK = false;
        }

        out.open(outFileName.c_str());
        if (out.fail()) {
            std::cerr << "Unable to open:" << outFileName << "\n";
            isOK = false;
        }

        if (isOK)
            handlePrefix();
    }

    ~FileTemplate()
    {
        if (isOK)
            handleSuffix();
    }

    // Goes until @generate..
    void handlePrefix()
    {
        out << "// WARNING: Portions of this file are autogenerated from codes.def and " << inFileName << ".\n";
        out << "// (which is what the licensing terms apply to)\n";
        out << "// Any changes you make here may be lost!\n";

        out << "#line " << 1 << " \"" << inFileName << "\"\n";
        while (!in.eof()) {
            string line;
            getline(in, line);
            ++lines;
            if (stringEndsWith(line, "@generate"))
                break;
            else
                out << line << "\n";
        }
        // This is a little odd since we add 5 lines ourselves --
        // the 3 warning lines, and 2 #lines
        out << "#line " << (lines + 5) << " \"" << outFileName << "\"\n";
    }

    void handleSuffix()
    {
        out << "#line " << (lines + 1) << " \"" << inFileName << "\"\n";
        while (!in.eof()) {
            string line;
            getline(in, line);
            out << line << "\n";
        }
    }

    string   inFileName;
    string   outFileName;
    ifstream in;
    ofstream out;
    bool         isOK;
    bool ok() { return isOK; }
    int lines;
};

int main(int argc, char* argv[])
{
    if (argc != 2) {
        std::cerr << "Usage: icemaker <path>\n";
    }

    std::string path = std::string(argv[1]) + "/";

    ifstream def;
    def.open((path + "codes.def").c_str());
    if (def.fail()) {
        std::cerr << "Unable to open codes.def\n";
        return -1;
    }

    FileTemplate opcodesH  (path + "opcodes.h.in",   "opcodes.h");
    FileTemplate opcodesCpp(path + "opcodes.cpp.in", "opcodes.cpp");
    FileTemplate machineCpp(path + "machine.cpp.in", "machine.cpp");

    if (!opcodesH.ok() || !opcodesCpp.ok() || !machineCpp.ok())
        return -1;

    std::cout << "icemaker -40.9 for KJS/FrostByte\n";
    std::cout << "Generating bytecode instruction selection tables and VM dispatcher...\n";

    TableBuilder build(&def, &opcodesH.out, &opcodesCpp.out, &machineCpp.out);
    build.generateCode();
    return 0;
}

// kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on;
