File vm.hpp

File List > include > simplesquirrel > vm.hpp

Go to the documentation of this file.

#pragma once
#ifndef SSQ_VM_HEADER_H
#define SSQ_VM_HEADER_H

#include "exceptions.hpp"
#include "table.hpp"
#include "script.hpp"
#include "args.hpp"
#include "class.hpp"
#include "instance.hpp"
#include "function.hpp"
#include "array.hpp"

#include <memory>

#ifdef _MSC_VER
#pragma warning( push )
#pragma warning( disable: 4251 )
#endif

namespace ssq {
    typedef void(*SqPrintFunc)(HSQUIRRELVM, const SQChar*, ...);
    typedef void(*SqErrorFunc)(HSQUIRRELVM, const SQChar*, ...);
    typedef SQInteger(*SqRuntimeErrorFunc)(HSQUIRRELVM);
    typedef void(*SqCompileErrorFunc)(HSQUIRRELVM, const SQChar*, const SQChar*, SQInteger, SQInteger);
    class Libs {
    public:
        typedef int Flag;
        static const Flag NONE = 0x0000;
        static const Flag IO = 0x0001;
        static const Flag BLOB = 0x0002;
        static const Flag MATH = 0x0004;
        static const Flag SYSTEM = 0x0008;
        static const Flag STRING = 0x0010;
        static const Flag ALL = 0xFFFF;
    };

    class SSQ_API VM: public Table {
    public:
        VM(size_t stackSize, Libs::Flag flags = 0x00);
        void destroy();
        virtual ~VM();
        void swap(VM& other) NOEXCEPT;
        VM(const VM& other) = delete;
        VM(VM&& other) NOEXCEPT;
        void registerStdlib(Libs::Flag flags);
        void setPrintFunc(SqPrintFunc printFunc, SqErrorFunc errorFunc);
        void setRuntimeErrorFunc(SqRuntimeErrorFunc runtimeErrorFunc);
        void setCompileErrorFunc(SqCompileErrorFunc compileErrorFunc);
        SQInteger getTop() const;
        const CompileException& getLastCompileException() const {
            return *compileException.get();
        }
        const RuntimeException& getLastRuntimeException() const {
            return *runtimeException.get();
        }
        Script compileSource(const char* source, const char* name = "buffer");
        Script compileFile(const char* path);
        void run(const Script& script) const;
        template<class... Args>
        Object callFunc(const Function& func, const Object& env, Args&&... args) const {
            static const std::size_t params = sizeof...(Args);

            if(func.getNumOfParams() != params){
                throw RuntimeException("Number of arguments does not match");
            }

            auto top = sq_gettop(vm);
            sq_pushobject(vm, func.getRaw());
            sq_pushobject(vm, env.getRaw());

            pushArgs(std::forward<Args>(args)...);

            return callAndReturn(params, top);
        }
        template<class... Args>
        Instance newInstance(const Class& cls, Args&&... args) const {
            Instance inst = newInstanceNoCtor(cls);
            Function ctor = cls.findFunc("constructor");
            callFunc(ctor, inst, std::forward<Args>(args)...);
            return inst;
        }
        Instance newInstanceNoCtor(const Class& cls) const {
            Instance inst(vm);
            sq_pushobject(vm, cls.getRaw());
            sq_createinstance(vm, -1);
            sq_remove(vm, -2);
            sq_getstackobj(vm, -1, &inst.getRaw());
            sq_addref(vm, &inst.getRaw());
            sq_pop(vm, 1);
            return inst;
        }
        Table newTable() const {
            return Table(vm);
        }
        Array newArray() const {
            return Array(vm);
        }
        template<class T>
        Array newArray(const std::vector<T>& vector) const {
            return Array(vm, vector);
        }
        Enum addEnum(const char* name);
        template<typename T>
        inline void setConst(const char* name, const T& value) {
            sq_pushconsttable(vm);
            sq_pushstring(vm, name, strlen(name));
            detail::push<T>(vm, value);
            sq_newslot(vm, -3, false);
            sq_pop(vm,1); // pop table
        }
        void debugStack() const;
        void addClassObj(size_t hashCode, const HSQOBJECT& obj);
        const HSQOBJECT& getClassObj(size_t hashCode);
        VM& operator = (const VM& other) = delete;
        VM& operator = (VM&& other) NOEXCEPT;
    private:
        std::unique_ptr<CompileException> compileException;
        std::unique_ptr<RuntimeException> runtimeException;
        std::unordered_map<size_t, HSQOBJECT> classMap;

        static void pushArgs();

        template <class First, class... Rest> 
        void pushArgs(First&& first, Rest&&... rest) const {
            detail::push(vm, first);
            pushArgs(std::forward<Rest>(rest)...);
        }

        Object callAndReturn(SQUnsignedInteger nparams, SQInteger top) const;

        static void defaultPrintFunc(HSQUIRRELVM vm, const SQChar *s, ...);

        static void defaultErrorFunc(HSQUIRRELVM vm, const SQChar *s, ...);

        static SQInteger defaultRuntimeErrorFunc(HSQUIRRELVM vm);

        static void defaultCompilerErrorFunc(HSQUIRRELVM vm, const SQChar* desc, const SQChar* source, SQInteger line, SQInteger column);
    };
}

#ifdef _MSC_VER
#pragma warning( pop )
#endif

#endif