← index
MasterX_System/compiler/ETL/embed_func.cpp
Source: MasterX_System/compiler/ETL/embed_func.cpp
#include"embed_func.hpp"

#include<initializer_list>

#include<algorithm>

#include<cstring>

#include<ctime>

#include<cstdlib>

#include<fstream>

#include<dlfcn.h>




namespace lib { 

    void check_args(const std::string &n, const std::vector<interp::Var>  &v, std::initializer_list<ast::VarType> args) {
        if(v.size() != args.size()) {
            std::ostringstream stream;
            stream << "In function: " << n << " argument count mismatch.";
            throw interp::Exception(stream.str());
        }
        size_t i = 0;
        for(auto a = args.begin(); a != args.end(); ++a) {
            if(v.at(i).type != *a) {
                std::ostringstream stream;
                stream << "In function: " << n << " argumment type mismatch found " << ast::VarString[static_cast<int>(v.at(i).type)] << " expected " << ast::VarString[static_cast<int>(*a)];
                throw interp::Exception(stream.str());
            }
            i ++;
        }
    }

    interp::Var func_print(const std::vector<interp::Var> &v) {
        check_args("puts", v, {ast::VarType::STRING});
        std::cout << v.at(0).string_value << "\n";
        return interp::Var("return", (long)0);
    }

    interp::Var func_str(const std::vector<interp::Var> &v) {
        check_args("str", v, {ast::VarType::NUMBER});
        std::string value;
        value = std::to_string(v.at(0).numeric_value);
        return interp::Var("return", value);
    }

    interp::Var func_malloc(const std::vector<interp::Var> &v) {
        check_args("malloc", v, {ast::VarType::NUMBER});
        void *buf = nullptr;
        buf = (void*) malloc(v.at(0).numeric_value);
        return interp::Var("return", (void*)buf);
    }

    interp::Var func_free(const std::vector<interp::Var> &v) {
        check_args("free", v, {ast::VarType::POINTER});
        free(v.at(0).ptr_value);   
        return interp::Var("return", (long)0);
    }

    interp::Var func_scan_integer(const std::vector<interp::Var> &v) {
        check_args("scan_integer", v, {});
        std::string line;
        std::getline(std::cin, line);
        return interp::Var("return", (long)std::atol(line.c_str()));
    }

    interp::Var func_len(const std::vector<interp::Var> &v) {
        check_args("len", v, {ast::VarType::STRING});
        return interp::Var("return", (long)v.at(0).string_value.length());
    }

    interp::Var func_exit(const std::vector<interp::Var> &v) {
        check_args("exit", v, {ast::VarType::NUMBER});
        exit(v.at(0).numeric_value);
        return interp::Var("return", (long)0);
    }
   
    interp::Var func_srand(const std::vector<interp::Var> &v) {
        check_args("srand", v, {ast::VarType::NUMBER});
        srand(v.at(0).numeric_value);
        return interp::Var("return", (long)0);
    }

    interp::Var func_rand(const std::vector<interp::Var> &v) {
        check_args("rand", v, {});
        return interp::Var("return", (long)rand());
    }

    interp::Var func_time(const std::vector<interp::Var> &v) {
        check_args("time", v, {ast::VarType::NUMBER});
        int t = time(0);
        return interp::Var("return", (long)t);
    }

    interp::Var func_strlen(const std::vector<interp::Var> &v) {
        check_args("strlen", v, {ast::VarType::STRING});
        return interp::Var("return", (long)v.at(0).string_value.length());
    }

    interp::Var func_strcmp(const std::vector<interp::Var> &v) {
        check_args("strcmp", v, {ast::VarType::STRING, ast::VarType::STRING});
        return interp::Var("return", (long)strcmp(v.at(0).string_value.c_str(), v.at(1).string_value.c_str()));
    }

    interp::Var func_at(const std::vector<interp::Var> &v) {
        check_args("at", v,{ast::VarType::STRING, ast::VarType::NUMBER});
        return interp::Var("return", (long)v.at(0).string_value.at(v.at(1).numeric_value));
    }

    interp::Var func_char_at(const std::vector<interp::Var> &v) {
        check_args("charAt", v,{ast::VarType::STRING, ast::VarType::NUMBER});
        char *buf = (char*)malloc(2);
        buf[0] = v.at(0).string_value.at(v.at(1).numeric_value);
        return interp::Var("return", (void*)buf);
    }

    interp::Var func_ptr(const std::vector<interp::Var> &v) {
        check_args("ptr", v,{ast::VarType::STRING});
        return interp::Var("return", (void*)v.at(0).string_value.data());
    }

    interp::Var func_string(const std::vector<interp::Var> &v) {
        check_args("string", v,{ast::VarType::POINTER});
        return interp::Var("return", std::string((char*)v.at(0).ptr_value));
    }

    interp::Var func_calloc(const std::vector<interp::Var> &v) {
        check_args("calloc", v, {ast::VarType::NUMBER});
        void *buf = nullptr;
        buf = (void*) calloc(1, v.at(0).numeric_value);
        return interp::Var("return", (void*)buf);
    }

    interp::Var func_mematl(const std::vector<interp::Var> &v) {
        check_args("mematl", v, {ast::VarType::POINTER, ast::VarType::NUMBER});
        long *value = (long *)v.at(0).ptr_value;
        if(value == nullptr) 
            throw interp::Exception("Null pointer [mematl] " + v.at(0).name);
        
        return interp::Var("return", (long)value[v.at(1).numeric_value]);
    }

    interp::Var func_mematb(const std::vector<interp::Var> &v) {
        check_args("mematb", v, {ast::VarType::POINTER, ast::VarType::NUMBER});
        char *value = (char *)v.at(0).ptr_value;
        if(value == nullptr) 
            throw interp::Exception("Null pointer [mematb] " + v.at(0).name);

        return interp::Var("return", (long)value[v.at(1).numeric_value]);
    }

    interp::Var func_memclr(const std::vector<interp::Var> &v) {
        check_args("memclr", v, {ast::VarType::POINTER, ast::VarType::NUMBER});
        memset(v.at(0).ptr_value, 0, v.at(1).numeric_value);
        return interp::Var("return", (long)0);
    }

    interp::Var func_memstorel(const std::vector<interp::Var> &v) {
        check_args("memstorel", v, {ast::VarType::POINTER, ast::VarType::NUMBER, ast::VarType::NUMBER});
        long *value = (long *)v.at(0).ptr_value;
        if(value == nullptr) {
            throw interp::Exception("Null pointer [memstorel] " + v.at(0).name);
        }
        value[v.at(1).numeric_value] = v.at(2).numeric_value;
        return interp::Var("return", (long)0);
    }

    interp::Var func_memstoreb(const std::vector<interp::Var> &v) {
        check_args("memstoreb", v, {ast::VarType::POINTER, ast::VarType::NUMBER, ast::VarType::NUMBER});
        char *value = (char *)v.at(0).ptr_value;
        if(value == nullptr) {
            throw interp::Exception("Null pointer [memstoreb] " + v.at(0).name);
        }
        value[v.at(1).numeric_value] = (char)v.at(2).numeric_value;
        return interp::Var("return", (long)0);
    }

    interp::Var func_memcpy(const std::vector<interp::Var> &v) {
        check_args("memcpy", v, {ast::VarType::POINTER, ast::VarType::POINTER, ast::VarType::NUMBER});
        void *b = memcpy(v.at(0).ptr_value, v.at(1).ptr_value, v.at(2).numeric_value);
        return interp::Var("return", (void *)b);
    }

    interp::Var func_release(const std::vector<interp::Var> &v) {
        check_args("release", v, {ast::VarType::STRING});
        return interp::Var("return", (long)0);
    }

    interp::Var func_string_int(const std::vector<interp::Var> &v) {
        check_args("string_int", v, {ast::VarType::POINTER, ast::VarType::NUMBER});
        std::string value = std::to_string(v.at(1).numeric_value);
        strcpy((char*)v.at(0).ptr_value, value.c_str());
        return interp::Var("return", (long)0);
    }


    interp::Var func_printf(const std::vector<interp::Var> &v) {       
        if(v.size() > 0) {
            std::string input = v.at(0).string_value;
            size_t index = 1;
            for(size_t i = 0; i < input.length(); ++i) {
                if(input.at(i) != '%') {
                    std::cout << input.at(i);
                    continue;
                } 
                if(i+1 < input.length() && input.at(i+1) == '%') {
                    std::cout << '%';
                    i++;
                    continue;
                } else if(i+1 < input.length()) {
                    char c = input.at(i+1);
                    if(index < v.size()) {
                        switch(v.at(index).type) {
                            case ast::VarType::STRING:
                            std::cout << v.at(index).string_value;
                            break;
                            case ast::VarType::NUMBER:
                                if(c == 'c')
                                    std::cout << (char)v.at(index).numeric_value;
                                else 
                                    std::cout << (long)v.at(index).numeric_value;
                            break;
                            case ast::VarType::POINTER:
                            std::cout << (long)v.at(index).ptr_value;
                            break;
                            default:
                            break;
                        }
                    }
                    index ++;
                    i ++;
                }
            }
        }
        return interp::Var("return", (long)0);
    }

     interp::Var func_sprintf(const std::vector<interp::Var> &v) {
        if(v.size() >= 2) {
            void *buf = v.at(0).ptr_value;
            std::ostringstream stream;
            std::string input = v.at(1).string_value;
            size_t index = 2;
            for(size_t i = 0; i < input.length(); ++i) {
                if(input.at(i) != '%') {
                    stream << input.at(i);
                    continue;
                } 
                if(i+1 < input.length() && input.at(i+1) == '%') {
                    stream << '%';
                    i++;
                    continue;
                } else if(i+1 < input.length()) {
                    char c = input.at(i+1);
                    if(index < v.size()) {
                        switch(v.at(index).type) {
                            case ast::VarType::STRING:
                            stream << v.at(index).string_value;
                            break;
                            case ast::VarType::NUMBER:
                                if(c == 'c')
                                    stream << (char)v.at(index).numeric_value;
                                else 
                                    stream << (long)v.at(index).numeric_value;
                            break;
                            case ast::VarType::POINTER:
                            stream << (long)v.at(index).ptr_value;
                            break;
                            default:
                            break;
                        }
                    }
                    index ++;
                    i ++;
                }
                strcpy((char*)buf, stream.str().c_str());
            }
            return interp::Var("return", stream.str());
        }
        return interp::Var("return", "");
        
    }


    std::unordered_map<std::string, interp::FuncPtr> func_table  { 
        {"puts", func_print}, 
        {"str", func_str},
        {"malloc", func_malloc},
        {"free", func_free},
        {"scan_integer", func_scan_integer},
        {"len", func_len},
        {"exit", func_exit},
        {"srand",  func_srand},
        {"rand", func_rand},
        {"time", func_time},
        {"strlen", func_strlen},
        {"strcmp", func_strcmp},
        {"at", func_at},
        {"charAt", func_char_at},
        {"ptr", func_ptr},
        {"string", func_string},
        {"calloc", func_calloc},
        {"mematl", func_mematl},
        {"mematb", func_mematb},
        {"memclr", func_memclr},
        {"memstorel", func_memstorel},
        {"memstoreb", func_memstoreb},
        {"memcpy", func_memcpy},
        {"release", func_release},
        {"printf", func_printf},
        {"sprintf", func_sprintf}
    };



    
    std::vector<void *> shared_objects;

    void addFunc(const char *src, void *ptr) {
        func_table[std::string(src)] = (interp::FuncPtr)ptr;
    }

     void initSharedObject(const std::string &n, const std::string &init_func) {
        std::string path = n;
#ifdef __APPLE__

        path += ".dylib";
#else

        path += ".so";
#endif

        void *obj = dlopen(path.c_str(), RTLD_NOW);
        if(!obj) {
            std::cerr << "ETL: Error opening shared library: " << path << "\n";
            char *e = dlerror();
            if(e) {
                std::cerr << "Error: " << e << "\n";
            }
            std::cerr.flush();
            exit(EXIT_FAILURE);
        }
        dlerror();
        shared_objects.push_back(obj);
        typedef void  (*addFunction)(const char *src, void *ptr);
        typedef void (*initTable)(addFunction);
        initTable table = (initTable)dlsym(obj, init_func.c_str());
        char *err = dlerror();
        if(err) {
            std::cerr << "ETL: Could not get Pointer to table function: " << err << "\n";
            std::cerr.flush();
            exit(EXIT_FAILURE);
        }
        std::cout << "ETL: Loaded Shared Library: " << path << "\n";
        table(addFunc);
    }

#ifdef WITH_STATIC_SDL

    void initStatic() {
        libsdl_rt_initTable(addFunc);
        libio_rt_initTable(addFunc);
    }
#endif


    void loadSharedObjects(const std::string &lib_path, const std::string &filename) {
        std::fstream file;
        file.open(filename, std::ios::in);
        while(!file.eof()) {
            std::string line;
            std::getline(file, line);
            if(file) {
                std::string name = line.substr(line.rfind("/")+1);
                std::string tname = name + "_initTable";
                initSharedObject(lib_path + "/" + line, tname);
            }
        }
        file.close();
    }

    void releaseSharedObjects() {
        for(auto &i : shared_objects) {
            dlclose(i);
        }
    }
    
}