trash/ppc-lang

Clone repo: git clone https://git.topcheto.eu/trash/ppc-lang.git
All branches, All tags, View raw

File contents

#include <vector>
#include <fstream>
#include <iostream>

struct project_t {
    std::string output;
    std::vector<std::string> deps;
};

std::string read_str(std::istream &f, const std::string &skip_chars, const std::string &end_chars, int &end_char) {
    std::vector<char> res { };
    int c;

    while (true) {
        c = f.get();
        auto a = end_chars.find(c);
        if (c == -1 || a != std::string::npos) {
            end_char = c;
            return "";
        }
        if ((a = skip_chars.find(c)) == std::string::npos) {
            f.unget();
            break;
        }
    }

    while (true) {
        c = f.get();
        if (c == -1 || end_chars.find(c) != std::string::npos) {
            end_char = c;
            break;
        }

        res.push_back(c);
    }
    while (true) {
        if (skip_chars.find(res.back()) != std::string::npos) res.pop_back();
        else break;
    }

    return std::string { res.begin(), res.end() };
}
std::string read_str(std::istream &f, const std::string &skip_chars, const std::string &end_chars) {
    int end_char;
    return read_str(f, skip_chars, end_chars, end_char);
}

project_t read_project(std::istream &f) {
    int end_ch;
    std::string name = read_str(f, " \v\t\r\n", "\n", end_ch);
    std::size_t cap = 16, n = 0;
    std::vector<std::string> deps { };

    if (name.length() == 0) {
        throw (std::string)"The name of a project may not be empty.";
    }

    if (end_ch == -1) {
        return project_t {
            .output = name,
            .deps = deps,
        };
    }

    if (name.find(',') != std::string::npos || name.find(' ') != std::string::npos) {
        throw (std::string)"The name of a project may not contain spaces or commas.";
    }

    while (true) {
        std::string dep = read_str(f, " \v\t\r\n", ",\n", end_ch);

        if (dep.find(' ') != std::string::npos) {
            throw (std::string)"The name of a dependency may not contain spaces.";
        }

        if (dep.length()) {
            deps.push_back(dep);
            if (end_ch == '\n') break;
        }
        if (end_ch == -1) break;
    }

    return project_t {
        .output = name,
        .deps = deps,
    };
}

void print_err(const std::string &error, const std::string &context) {
    std::cerr << context << ": " << error;
}

int main(int argc, const char* argv[]) {
    std::string proj_name = "";
    try {
        argc--;
        argv++;

        if (argc != 3) {
            throw (std::string)"Incorrect usage. Syntax: [src-dir] [project-name] [output|deps].";
        }

        std::string proj_path = (std::string)argv[0] + "/" + argv[1] + ".proj";
        proj_name = argv[1];

        std::ifstream f { proj_path, std::ios_base::in };

        if (!f.is_open()) {
            throw (std::string)"The project '" + argv[1] +"' doesn't exist.";
        }

        project_t project = read_project(f);
        f.close();

        if ((std::string)argv[2] == "output") {
            std::cout << project.output;
        }
        else if ((std::string)argv[2] == "deps") {
            for (std::string dep : project.deps) {
                std::cout << dep << " ";
            }
        }
        else {
            throw (std::string)"Invalid command given. Available commands: output, deps.";
        }

        std::cout << std::endl;

        return 0;
    }
    catch (std::string err) {
        if (proj_name.length()) std::cerr << "Error: " << proj_name << ": " << err << std::endl;
        else std::cerr << "Error: " << err << std::endl;
    }
    return -1;
}